aboutsummaryrefslogtreecommitdiffstats
path: root/libccnx-common
diff options
context:
space:
mode:
authorLuca Muscariello <lumuscar+fdio@cisco.com>2017-02-23 20:44:26 +0100
committerLuca Muscariello <lumuscar+fdio@cisco.com>2017-02-23 19:51:14 +0000
commitd18ae43123fcd7604d1c36a1ec8450dbe6071824 (patch)
tree2d49fc3aabd0f2607251c854565648d47b56b2e9 /libccnx-common
parent9b30fc10fb1cbebe651e5a107e8ca5b24de54675 (diff)
Initial commit: ccnxlibs.
Change-Id: I1b376527a7dd01a6b9e083a6cb646955902f45c0 Signed-off-by: Luca Muscariello <lumuscar+fdio@cisco.com>
Diffstat (limited to 'libccnx-common')
-rw-r--r--libccnx-common/.gitignore99
-rw-r--r--libccnx-common/AUTHORS13
-rw-r--r--libccnx-common/BASE_VERSION1
-rw-r--r--libccnx-common/CMakeLists.txt75
-rw-r--r--libccnx-common/LICENSE13
-rw-r--r--libccnx-common/README.md81
-rw-r--r--libccnx-common/ccnx/common/.gitignore2
-rw-r--r--libccnx-common/ccnx/common/CMakeLists.txt272
-rw-r--r--libccnx-common/ccnx/common/Groups.dox16
-rw-r--r--libccnx-common/ccnx/common/ccnx_ContentObject.c406
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_ContentObject.h677
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_Interest.c399
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_Interest.h807
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_InterestPayloadId.c216
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_InterestPayloadId.h518
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_InterestReturn.c144
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_InterestReturn.h299
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_KeyLocator.c236
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_KeyLocator.h376
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_KeystoreUtilities.c308
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_KeystoreUtilities.h171
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_Link.c180
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_Link.h263
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_Manifest.c179
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_Manifest.h307
-rw-r--r--libccnx-common/ccnx/common/ccnx_ManifestHashGroup.c592
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_ManifestHashGroup.h692
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_Name.c417
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_Name.h738
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_NameLabel.c316
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_NameLabel.h374
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_NameSegment.c308
-rw-r--r--libccnx-common/ccnx/common/ccnx_NameSegment.h566
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_NameSegmentNumber.c77
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_NameSegmentNumber.h121
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_PayloadType.h37
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_TimeStamp.c144
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_TimeStamp.h336
-rw-r--r--libccnx-common/ccnx/common/ccnx_WireFormatMessage.c326
-rwxr-xr-xlibccnx-common/ccnx/common/ccnx_WireFormatMessage.h422
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.c559
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.h300
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_Error.c173
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_Error.h190
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_ErrorCodes.h55
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.c809
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.h833
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.c320
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.h677
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.c382
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.h755
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.c190
-rwxr-xr-xlibccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.h135
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.c173
-rw-r--r--libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.h441
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.c137
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h85
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h51
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.c210
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h165
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.c64
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h50
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c149
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h74
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c165
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h76
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c187
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h52
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c166
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h31
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.c140
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h57
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.c340
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h47
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c85
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h83
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c59
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h64
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.c125
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h144
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.c187
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h46
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c289
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h91
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c353
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h85
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.c68
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h250
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h211
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.c176
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h74
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.c253
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h79
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore19
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt29
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c154
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c350
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c174
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c235
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c450
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c267
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c306
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c320
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c644
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c139
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c149
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c321
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c205
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c684
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c1054
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c118
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c450
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c565
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c472
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c516
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/CMakeLists.txt27
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h50
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h74
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h54
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h114
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h181
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h65
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h55
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h57
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h50
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h78
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h102
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h57
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h74
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h75
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_badcrc32c.h76
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h102
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h74
-rw-r--r--libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthSet.h68
-rwxr-xr-xlibccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h34
-rw-r--r--libccnx-common/ccnx/common/codec/test/.gitignore7
-rw-r--r--libccnx-common/ccnx/common/codec/test/CMakeLists.txt24
-rwxr-xr-xlibccnx-common/ccnx/common/codec/test/test_ccnxCodec_EncodingBuffer.c343
-rwxr-xr-xlibccnx-common/ccnx/common/codec/test/test_ccnxCodec_Error.c139
-rwxr-xr-xlibccnx-common/ccnx/common/codec/test/test_ccnxCodec_NetworkBuffer.c952
-rwxr-xr-xlibccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvDecoder.c808
-rwxr-xr-xlibccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvEncoder.c874
-rw-r--r--libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c447
-rw-r--r--libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvUtilities.c496
-rw-r--r--libccnx-common/ccnx/common/codec/test/test_random_bytesbin0 -> 512 bytes
-rw-r--r--libccnx-common/ccnx/common/codec/test/test_random_bytes.sigbin0 -> 128 bytes
-rw-r--r--libccnx-common/ccnx/common/codec/test/test_rsa.p12bin0 -> 1598 bytes
-rw-r--r--libccnx-common/ccnx/common/codec/test/test_rsa_key.pem15
-rwxr-xr-xlibccnx-common/ccnx/common/codec/test/testrig_Compare.c90
-rw-r--r--libccnx-common/ccnx/common/codec/testdata/testdata_common.h111
-rwxr-xr-xlibccnx-common/ccnx/common/codec/testdata/tlv_Schema.h29
-rw-r--r--libccnx-common/ccnx/common/config.h.in4
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.c60
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.h103
-rw-r--r--libccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.c294
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.h34
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.c54
-rw-r--r--libccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.h145
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_InterestDefault.c24
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_InterestDefault.h50
-rw-r--r--libccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.c295
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.h29
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_InterestInterface.c53
-rw-r--r--libccnx-common/ccnx/common/internal/ccnx_InterestInterface.h130
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_InterestPayloadIdMethod.h28
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.c100
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.h29
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.c55
-rw-r--r--libccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.h71
-rw-r--r--libccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.c132
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.h30
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_ManifestInterface.c55
-rw-r--r--libccnx-common/ccnx/common/internal/ccnx_ManifestInterface.h64
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_MessageInterface.h33
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_TlvDictionary.c1022
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_TlvDictionary.h1127
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_TlvError.c167
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.c203
-rw-r--r--libccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.h474
-rw-r--r--libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.c484
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.h42
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.c46
-rwxr-xr-xlibccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.h121
-rw-r--r--libccnx-common/ccnx/common/internal/test/.gitignore18
-rw-r--r--libccnx-common/ccnx/common/internal/test/CMakeLists.txt24
-rwxr-xr-xlibccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacadebin0 -> 185076 bytes
-rwxr-xr-xlibccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacadeV1.c261
-rwxr-xr-xlibccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacadebin0 -> 206292 bytes
-rw-r--r--libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacadeV1.c377
-rwxr-xr-xlibccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectInterface.c106
-rwxr-xr-xlibccnx-common/ccnx/common/internal/test/test_ccnx_InterestFacadeV1.c334
-rwxr-xr-xlibccnx-common/ccnx/common/internal/test/test_ccnx_InterestInterface.c107
-rwxr-xr-xlibccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnFacadeV1.c168
-rwxr-xr-xlibccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnInterface.c112
-rw-r--r--libccnx-common/ccnx/common/internal/test/test_ccnx_ManifestFacadeV1.c.c223
-rwxr-xr-xlibccnx-common/ccnx/common/internal/test/test_ccnx_ManifestInterface.c.c100
-rwxr-xr-xlibccnx-common/ccnx/common/internal/test/test_ccnx_TlvDictionary.c1142
-rwxr-xr-xlibccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacadebin0 -> 207544 bytes
-rwxr-xr-xlibccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacadeV1.c444
-rwxr-xr-xlibccnx-common/ccnx/common/internal/test/test_ccnx_WireFormatFacadeV1.c594
-rw-r--r--libccnx-common/ccnx/common/libccnxCommon_About.c44
-rwxr-xr-xlibccnx-common/ccnx/common/libccnxCommon_About.h54
-rw-r--r--libccnx-common/ccnx/common/test/.gitignore22
-rw-r--r--libccnx-common/ccnx/common/test/CMakeLists.txt29
-rw-r--r--libccnx-common/ccnx/common/test/data.json2614
-rwxr-xr-xlibccnx-common/ccnx/common/test/test_ccnx_ContentObject.c634
-rwxr-xr-xlibccnx-common/ccnx/common/test/test_ccnx_Interest.c725
-rwxr-xr-xlibccnx-common/ccnx/common/test/test_ccnx_InterestPayloadId.c469
-rwxr-xr-xlibccnx-common/ccnx/common/test/test_ccnx_InterestReturn.c285
-rwxr-xr-xlibccnx-common/ccnx/common/test/test_ccnx_Key.c175
-rwxr-xr-xlibccnx-common/ccnx/common/test/test_ccnx_KeyLocator.c358
-rw-r--r--libccnx-common/ccnx/common/test/test_ccnx_KeystoreUtilities.c255
-rwxr-xr-xlibccnx-common/ccnx/common/test/test_ccnx_Link.c296
-rwxr-xr-xlibccnx-common/ccnx/common/test/test_ccnx_Manifest.c359
-rw-r--r--libccnx-common/ccnx/common/test/test_ccnx_ManifestHashGroup.c515
-rw-r--r--libccnx-common/ccnx/common/test/test_ccnx_Name.c735
-rwxr-xr-xlibccnx-common/ccnx/common/test/test_ccnx_NameLabel.c470
-rw-r--r--libccnx-common/ccnx/common/test/test_ccnx_NameSegment.c739
-rwxr-xr-xlibccnx-common/ccnx/common/test/test_ccnx_NameSegmentNumber.c241
-rwxr-xr-xlibccnx-common/ccnx/common/test/test_ccnx_TimeStamp.c217
-rwxr-xr-xlibccnx-common/ccnx/common/test/test_ccnx_WireFormatMessage.c502
-rw-r--r--libccnx-common/ccnx/common/validation/ccnxValidation_CRC32C.c214
-rwxr-xr-xlibccnx-common/ccnx/common/validation/ccnxValidation_CRC32C.h87
-rwxr-xr-xlibccnx-common/ccnx/common/validation/ccnxValidation_EcSecp256K1.c75
-rwxr-xr-xlibccnx-common/ccnx/common/validation/ccnxValidation_EcSecp256K1.h129
-rw-r--r--libccnx-common/ccnx/common/validation/ccnxValidation_HmacSha256.c100
-rwxr-xr-xlibccnx-common/ccnx/common/validation/ccnxValidation_HmacSha256.h100
-rw-r--r--libccnx-common/ccnx/common/validation/ccnxValidation_RsaSha256.c51
-rwxr-xr-xlibccnx-common/ccnx/common/validation/ccnxValidation_RsaSha256.h68
-rw-r--r--libccnx-common/ccnx/common/validation/test/.gitignore4
-rw-r--r--libccnx-common/ccnx/common/validation/test/CMakeLists.txt16
-rwxr-xr-xlibccnx-common/ccnx/common/validation/test/test_ccnxValidation_CRC32C.c203
-rwxr-xr-xlibccnx-common/ccnx/common/validation/test/test_ccnxValidation_EcSecp256K1.c116
-rwxr-xr-xlibccnx-common/ccnx/common/validation/test/test_ccnxValidation_HmacSha256.c130
-rwxr-xr-xlibccnx-common/ccnx/common/validation/test/test_ccnxValidation_RsaSha256.c118
-rwxr-xr-xlibccnx-common/ccnx/common/validation/test/testrig_validation.c298
-rw-r--r--libccnx-common/cmake/Modules/FindLibEvent.cmake47
-rw-r--r--libccnx-common/cmake/Modules/FindLibparc.cmake39
-rw-r--r--libccnx-common/cmake/Modules/FindLongBow.cmake44
-rw-r--r--libccnx-common/cmake/Modules/FindUncrustify.cmake8
-rw-r--r--libccnx-common/cmake/Modules/detectCacheSize.cmake21
-rw-r--r--libccnx-common/cmake/Modules/version.cmake15
-rwxr-xr-xlibccnx-common/cmake/get_version.sh20
-rw-r--r--libccnx-common/documentation/.gitignore9
-rw-r--r--libccnx-common/documentation/CMakeLists.txt49
-rw-r--r--libccnx-common/documentation/DoxygenLayout.xml196
-rw-r--r--libccnx-common/documentation/Makefile.am89
-rw-r--r--libccnx-common/documentation/Makefile.notautomake76
-rw-r--r--libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css470
-rw-r--r--libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css.map1
-rw-r--r--libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.min.css5
-rw-r--r--libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap.css6332
-rw-r--r--libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap.css.map1
-rw-r--r--libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap.min.css5
-rw-r--r--libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eotbin0 -> 20335 bytes
-rw-r--r--libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.svg229
-rw-r--r--libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttfbin0 -> 41280 bytes
-rw-r--r--libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woffbin0 -> 23320 bytes
-rw-r--r--libccnx-common/documentation/doxygen-extras/bootstrap/js/bootstrap.js2320
-rw-r--r--libccnx-common/documentation/doxygen-extras/bootstrap/js/bootstrap.min.js7
-rw-r--r--libccnx-common/documentation/doxygen-extras/bootstrap/js/npm.js13
-rw-r--r--libccnx-common/documentation/doxygen-extras/customdoxygen.css1705
-rw-r--r--libccnx-common/documentation/doxygen-extras/doxy-boot.js120
-rwxr-xr-xlibccnx-common/documentation/doxygen-extras/doxygen-bootstrap.js119
-rwxr-xr-xlibccnx-common/documentation/doxygen-extras/footer.html31
-rwxr-xr-xlibccnx-common/documentation/doxygen-extras/header.html47
-rw-r--r--libccnx-common/documentation/doxygen-extras/masthead.css9
-rw-r--r--libccnx-common/documentation/examples/README.md0
-rw-r--r--libccnx-common/documentation/images/parc_black_solid.pngbin0 -> 24543 bytes
-rw-r--r--libccnx-common/documentation/libccnx-stage1.doxygen.in2385
-rw-r--r--libccnx-common/documentation/libccnx-stage2.doxygen.in2389
-rw-r--r--libccnx-common/documentation/libccnx_api_control-stage1.doxygen2424
-rw-r--r--libccnx-common/documentation/libccnx_api_control-stage2.doxygen2424
-rw-r--r--libccnx-common/documentation/libccnx_api_notify-stage1.doxygen2422
-rw-r--r--libccnx-common/documentation/libccnx_api_notify-stage2.doxygen2420
-rw-r--r--libccnx-common/documentation/libccnx_api_portal-stage1.doxygen2424
-rw-r--r--libccnx-common/documentation/libccnx_api_portal-stage2.doxygen2423
-rw-r--r--libccnx-common/documentation/librta-stage1.doxygen2415
-rw-r--r--libccnx-common/documentation/librta-stage2.doxygen2420
-rw-r--r--libccnx-common/documentation/stylesheet.css47
280 files changed, 93142 insertions, 0 deletions
diff --git a/libccnx-common/.gitignore b/libccnx-common/.gitignore
new file mode 100644
index 00000000..e47da092
--- /dev/null
+++ b/libccnx-common/.gitignore
@@ -0,0 +1,99 @@
+aVERSION
+.cproject
+.project
+*.plist
+libccnx*.tar.gz
+
+.idea/
+
+LongBow
+include
+lib
+.DS_Store
+*.o
+*.lo
+build/
+conf.mk
+*.dSYM
+*.gcda
+*.gcno
+*.gcov
+*.a
+*.la
+.libs
+conf.mk
+.deps
+config.log
+config.h
+config.status
+*.log
+*.trs
+.dirstamp
+Makefile
+stamp-h1
+
+transport/common/test/test_keyvalue
+transport/transport_rta/test/test_multi_connections
+transport/transport_rta/test/rtatest
+transport/transport_rta/test/test_bent_pipe
+transport/transport_rta/test/test_multi_connections
+transport/transport_rta/test/x
+transport/transport_rta/test/y
+transport/transport_rta/tlv/test/x
+transport/transport_rta/tlv/test/y
+transport/transport_rta/tlv/test/tlvtest
+transport/transport_rta/test/test_fc_vegas
+
+ccnx/api/control/test/test_cpi_Interface
+ccnx/api/control/test/test_cpi_InterfaceSet
+ccnx/api/control/test/test_cpi_InterfaceIPTunnelList
+ccnx/api/control/test/test_cpi_CancelFlow
+ccnx/api/control/test/test_cpi_Connection
+ccnx/api/control/test/test_cpi_ConnectionList
+ccnx/api/control/test/test_cpi_ManageForwarding
+ccnx/api/control/test/test_cpi_ManageLinks
+ccnx/api/control/test/test_cpi_RouteEntryList
+
+ccnx/api/ccnx_Portal/test/ccnxPortalFactory_keystore
+ccnx/api/ccnx_Portal/test/my_keystore
+
+autom4te.cache/
+
+*.xcuserdatad
+
+ccnx/transport/transport_rta/components/test/test_component_Codec_Tlv
+ccnx/transport/transport_rta/components/test/test_component_Codec_Tlv_Hmac
+ccnx/transport/transport_rta/components/test/test_fc_vegas
+ccnx/transport/transport_rta/config/test/test_config_ApiConnector
+ccnx/transport/transport_rta/config/test/test_config_Codec_Null
+ccnx/transport/transport_rta/config/test/test_config_Codec_Tlv
+ccnx/transport/transport_rta/config/test/test_config_FlowControl_Vegas
+ccnx/transport/transport_rta/config/test/test_config_Forwarder_Local
+ccnx/transport/transport_rta/config/test/test_config_Forwarder_Metis
+ccnx/transport/transport_rta/config/test/test_config_InMemoryVerifier
+ccnx/transport/transport_rta/config/test/test_config_ProtocolStack
+ccnx/transport/transport_rta/config/test/test_config_PublicKeySignerPkcs12Store
+ccnx/transport/transport_rta/config/test/test_config_Signer
+ccnx/transport/transport_rta/config/test/test_config_SymmetricKeySignerFileStore
+ccnx/transport/transport_rta/config/test/test_config_TestingComponent
+ccnx/transport/transport_rta/config/test/test_config_Verifier_Enumerated
+ccnx/transport/transport_rta/config/test/test_config_Verifier_Null
+ccnx/transport/transport_rta/connectors/test/test_connector_Api
+ccnx/transport/transport_rta/connectors/test/test_connector_Forwarder_Local
+ccnx/transport/transport_rta/connectors/test/test_connector_Forwarder_Metis
+ccnx/transport/transport_rta/core/test/test_rta_Commands
+ccnx/transport/transport_rta/core/test/test_rta_ConnectionTable
+ccnx/transport/transport_rta/core/test/test_rta_Framework
+ccnx/transport/transport_rta/core/test/test_rta_Framework_Commands
+ccnx/transport/transport_rta/test/test_rta_Transport
+
+*.doctags
+
+libtool
+*~
+test_ccnx_InterestReturnFacadeV1
+test_ccnx_InterestReturn
+lcov_report
+lcov.info
+test_ccnx_InterestReturnImplementation
+test_ccnx_InterestPayloadId
diff --git a/libccnx-common/AUTHORS b/libccnx-common/AUTHORS
new file mode 100644
index 00000000..c4c6fde5
--- /dev/null
+++ b/libccnx-common/AUTHORS
@@ -0,0 +1,13 @@
+Libccnx-common authors are listed below
+
+ Michele Papalini <micpapal@cisco.com>
+ Glenn Scott <Glenn.Scott@parc.com>
+ Kevin Fox <Kevin.Fox@parc.com>
+ Alan Walendowski <Alan.Walendowski@parc.com>
+ Marc Mosko <Marc.Mosko@parc.com>
+ Ignacio Solis
+ Michael Slominski
+
+Copyright (c) 2013-2016 Xerox Corporation (Xerox) and Palo Alto Reserch Center, Inc (PARC)
+Copyright (c) 2017 Cisco and/or its affiliates.
+
diff --git a/libccnx-common/BASE_VERSION b/libccnx-common/BASE_VERSION
new file mode 100644
index 00000000..d3827e75
--- /dev/null
+++ b/libccnx-common/BASE_VERSION
@@ -0,0 +1 @@
+1.0
diff --git a/libccnx-common/CMakeLists.txt b/libccnx-common/CMakeLists.txt
new file mode 100644
index 00000000..89c6024d
--- /dev/null
+++ b/libccnx-common/CMakeLists.txt
@@ -0,0 +1,75 @@
+cmake_minimum_required(VERSION 3.2)
+project(Libccnx-common)
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+
+set(CMAKE_C_STANDARD 99)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+
+if( UNIX )
+ link_libraries(m)
+endif( UNIX )
+
+include( CTest )
+include( version )
+include( detectCacheSize )
+
+if(ANDROID_API)
+ message("############ Detected cross compile for ${CMAKE_SYSTEM_NAME}")
+ message("############ This build will not include doxygen, tools, or tests")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ANDROID_C_FLAGS} -Wall")
+else()
+ # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -DNDEBUG -DLibccnx_DISABLE_VALIDATION")
+endif()
+
+#set(CMAKE_C_FLAGS_NOPANTS "${CMAKE_C_FLAGS_NOPANTS} -O3 -DNDEBUG -DLibccnx_DISABLE_VALIDATION")
+
+include_directories(${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR}/ccnx/common)
+
+include_directories($ENV{CCNX_DEPENDENCIES}/include)
+set(OPENSSL_ROOT_DIR $ENV{CCNX_DEPENDENCIES})
+
+find_package( LongBow REQUIRED )
+include_directories(${LONGBOW_INCLUDE_DIRS})
+
+find_package( LibEvent REQUIRED )
+include_directories(${LIBEVENT_INCLUDE_DIRS})
+
+find_package( Libparc REQUIRED )
+include_directories(${LIBPARC_INCLUDE_DIRS})
+
+find_package ( Threads REQUIRED )
+
+find_package ( OpenSSL REQUIRED )
+
+find_package( Doxygen )
+
+add_custom_target(${PROJECT_NAME}_cleanup_profiling_data
+ "find" "." "-name" "*.gcda" "-delete"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Cleanup previous profiling data.")
+
+if (ANDROID_API)
+ macro(AddTest testFile)
+ message("Android build: Skipping test ${ARGV0}")
+ endmacro(AddTest)
+else()
+ macro(AddTest testFile)
+ add_executable(${ARGV0} ${ARGV0}.c)
+ target_link_libraries(${ARGV0} ${LONGBOW_LIBRARIES})
+ target_link_libraries(${ARGV0} ccnx_common)
+ target_link_libraries(${ARGV0} ${LIBEVENT_LIBRARIES})
+ target_link_libraries(${ARGV0} ${LIBPARC_LIBRARIES})
+ target_link_libraries(${ARGV0} ${OPENSSL_LIBRARIES})
+ target_link_libraries(${ARGV0} ${CMAKE_THREAD_LIBS_INIT})
+ add_test(${ARGV0} ${ARGV0})
+ set_target_properties(${ARGV0} PROPERTIES FOLDER Test)
+ add_dependencies(${ARGV0} ${PROJECT_NAME}_cleanup_profiling_data)
+ endmacro(AddTest)
+endif()
+
+
+
+add_subdirectory(ccnx/common)
+add_subdirectory(documentation)
diff --git a/libccnx-common/LICENSE b/libccnx-common/LICENSE
new file mode 100644
index 00000000..77d3af5c
--- /dev/null
+++ b/libccnx-common/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2017 Cisco and/or its affiliates.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
diff --git a/libccnx-common/README.md b/libccnx-common/README.md
new file mode 100644
index 00000000..b0deb613
--- /dev/null
+++ b/libccnx-common/README.md
@@ -0,0 +1,81 @@
+Libccnx-common
+=======
+The CCNx Common Library
+
+## Quick Start ##
+```
+
+$ git clone -b cframework/master https://gerrit.fd.io/r/cicn ccnxlibs
+$ cd ccnxlibs/libccnx-common
+$ mkdir build
+$ cd build
+$ cmake ..
+$ make
+$ make test
+$ make install
+```
+
+## Introduction ##
+
+The CCNx Common library is a set of functions and data structures for CCNx.
+
+## Using Libccnx-common ##
+
+### Platforms ###
+
+Libccnx-common has been tested in:
+
+- Ubuntu 16.04 (x86_64)
+- Debian testing
+- MacOSX 10.12
+
+Other platforms and architectures may work.
+
+### Dependencies ###
+
+Build dependencies:
+
+- c99 ( clang / gcc )
+- CMake 3.4
+
+Basic dependencies:
+
+- OpenSSL
+- pthreads
+- Libevent
+- LongBow
+- Libparc
+
+
+Documentation dependencies:
+
+- Doxygen
+
+
+### Using Libccnx-common ###
+
+Libccnx-common is a set of functions and data structures for C. You can use it in your code by including the right header files and linking to the Libccnx-common library.
+
+```
+CCNX_HOME=<directory-where-Libccnx-common-is-installed>
+
+-I${CCNX_HOME}/include -L${CCNX_HOME}/lib -lccnx_common
+```
+
+### License ###
+This software is distributed under the following license:
+
+```
+Copyright (c) 2017 Cisco and/or its affiliates.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+```
diff --git a/libccnx-common/ccnx/common/.gitignore b/libccnx-common/ccnx/common/.gitignore
new file mode 100644
index 00000000..e81ef847
--- /dev/null
+++ b/libccnx-common/ccnx/common/.gitignore
@@ -0,0 +1,2 @@
+ccnx_LibraryVersion.c
+paths.c
diff --git a/libccnx-common/ccnx/common/CMakeLists.txt b/libccnx-common/ccnx/common/CMakeLists.txt
new file mode 100644
index 00000000..34e71e79
--- /dev/null
+++ b/libccnx-common/ccnx/common/CMakeLists.txt
@@ -0,0 +1,272 @@
+# Define a few configuration variables that we want accessible in the software
+
+set(VALIDATION_HDRS
+ validation/ccnxValidation_CRC32C.h
+ validation/ccnxValidation_EcSecp256K1.h
+ validation/ccnxValidation_HmacSha256.h
+ validation/ccnxValidation_RsaSha256.h
+ )
+
+source_group(validation FILES ${VALIDATION_HDRS})
+
+set(INTERNAL_HDRS
+ internal/ccnx_ChunkingFacadeV1.h
+ internal/ccnx_ContentObjectFacadeV1.h
+ internal/ccnx_ContentObjectInterface.h
+ internal/ccnx_InterestFacadeV1.h
+ internal/ccnx_InterestDefault.h
+ internal/ccnx_InterestInterface.h
+ internal/ccnx_InterestReturnFacadeV1.h
+ internal/ccnx_InterestReturnInterface.h
+ internal/ccnx_InterestPayloadIdMethod.h
+ internal/ccnx_ManifestFacadeV1.h
+ internal/ccnx_ManifestInterface.h
+ internal/ccnx_MessageInterface.h
+ internal/ccnx_TlvDictionary.h
+ internal/ccnx_ValidationFacadeV1.h
+ internal/ccnx_WireFormatFacadeV1.h
+ internal/ccnx_WireFormatMessageInterface.h
+ )
+
+source_group(internal FILES ${INTERNAL_HDRS})
+
+set(CODEC_HDRS
+ codec/ccnxCodec_EncodingBuffer.h
+ codec/ccnxCodec_Error.h
+ codec/ccnxCodec_ErrorCodes.h
+ codec/ccnxCodec_NetworkBuffer.h
+ codec/ccnxCodec_TlvEncoder.h
+ codec/ccnxCodec_TlvDecoder.h
+ codec/ccnxCodec_TlvUtilities.h
+ codec/ccnxCodec_TlvPacket.h
+ )
+
+source_group(codec FILES ${CODEC_HDRS})
+
+set(TESTDATA_HDRS
+ codec/testdata/tlv_Schema.h
+ codec/testdata/testdata_common.h
+ )
+
+set(SCHEMAV1_TESTDATA_HDRS
+ codec/schema_v1/testdata/v1_content_nameA_crc32c.h
+ codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h
+ codec/schema_v1/testdata/v1_content_no_payload.h
+ codec/schema_v1/testdata/v1_ContentObjectSchema.h
+ codec/schema_v1/testdata/v1_content_zero_payload.h
+ codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h
+ codec/schema_v1/testdata/v1_cpi_add_route.h
+ codec/schema_v1/testdata/v1_CPISchema.h
+ codec/schema_v1/testdata/v1_interest_all_fields.h
+ codec/schema_v1/testdata/v1_interest_bad_message_length.h
+ codec/schema_v1/testdata/v1_interest_bad_validation_alg.h
+ codec/schema_v1/testdata/v1_interest_nameA_badcrc32c.h
+ codec/schema_v1/testdata/v1_interest_nameA_crc32c.h
+ codec/schema_v1/testdata/v1_interest_nameA.h
+ codec/schema_v1/testdata/v1_InterestSchema.h
+ codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h
+ codec/schema_v1/testdata/v1_testrig_truthSet.h
+ codec/schema_v1/testdata/v1_testrig_truthTable.h
+ )
+
+source_group(schema_v1_testData FILES ${SCHEMAV1_TESTDATA_HDRS})
+
+set(SCHEMAV1_HDRS
+ codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h
+ codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h
+ codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h
+ codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h
+ codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h
+ codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h
+ codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h
+ codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h
+ codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h
+ codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h
+ codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h
+ codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h
+ codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h
+ codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h
+ codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h
+ codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h
+ codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h
+ codec/schema_v1/ccnxCodecSchemaV1_Types.h
+ codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h
+ codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h
+ )
+
+source_group(codec FILES ${SCHEMAV1_HDRS})
+
+set(CORE_HDRS
+ libccnxCommon_About.h
+ ccnx_ContentObject.h
+ ccnx_Interest.h
+ ccnx_InterestReturn.h
+ ccnx_InterestPayloadId.h
+ ccnx_KeyLocator.h
+ ccnx_KeystoreUtilities.h
+ ccnx_Link.h
+ ccnx_Manifest.h
+ ccnx_ManifestHashGroup.h
+ ccnx_Name.h
+ ccnx_NameSegment.h
+ ccnx_NameSegmentNumber.h
+ ccnx_NameLabel.h
+ ccnx_PayloadType.h
+ ccnx_TimeStamp.h
+ ccnx_WireFormatMessage.h
+ )
+
+source_group(core FILES ${CORE_HDRS})
+
+set(ALL_HDRS
+ ${VALIDATION_HDRS}
+ ${INTERNAL_HDRS}
+ ${CODEC_HDRS}
+ ${TESTDATA_HDRS}
+ ${SCHEMAV1_TESTDATA_HDRS}
+ ${SCHEMAV1_HDRS}
+ ${CORE_HDRS})
+
+set(VALIDATION_SRCS
+ validation/ccnxValidation_CRC32C.c
+ validation/ccnxValidation_EcSecp256K1.c
+ validation/ccnxValidation_HmacSha256.c
+ validation/ccnxValidation_RsaSha256.c
+ )
+
+source_group(validation FILES ${VALIDATION_SRCS})
+
+set(INTERNAL_SRCS
+ internal/ccnx_ChunkingFacadeV1.c
+ internal/ccnx_ContentObjectFacadeV1.c
+ internal/ccnx_ContentObjectInterface.c
+ internal/ccnx_InterestFacadeV1.c
+ internal/ccnx_InterestDefault.c
+ internal/ccnx_InterestInterface.c
+ internal/ccnx_InterestReturnFacadeV1.c
+ internal/ccnx_InterestReturnInterface.c
+ internal/ccnx_ManifestFacadeV1.c
+ internal/ccnx_ManifestInterface.c
+ internal/ccnx_TlvDictionary.c
+ internal/ccnx_ValidationFacadeV1.c
+ internal/ccnx_WireFormatFacadeV1.c
+ internal/ccnx_WireFormatMessageInterface.c
+ )
+
+source_group(internal FILES ${INTERNAL_SRCS})
+
+set(CODEC_V1_SRCS
+ codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.c
+ codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.c
+ codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.c
+ codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c
+ codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c
+ codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c
+ codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c
+ codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.c
+ codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.c
+ codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c
+ codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c
+ codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.c
+ codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.c
+ codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c
+ codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c
+ codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.c
+ codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.c
+ codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.c
+ )
+
+source_group(codec FILES ${CODEC_V1_SRCS})
+
+set(CODEC_SRCS
+ codec/ccnxCodec_EncodingBuffer.c
+ codec/ccnxCodec_Error.c
+ codec/ccnxCodec_NetworkBuffer.c
+ codec/ccnxCodec_TlvEncoder.c
+ codec/ccnxCodec_TlvDecoder.c
+ codec/ccnxCodec_TlvUtilities.c
+ codec/ccnxCodec_TlvPacket.c
+ ${CODEC_V1_SRCS}
+ )
+
+source_group(codec FILES ${CODEC_SRCS})
+
+set(CORE_SRCS
+ libccnxCommon_About.c
+ ccnx_ContentObject.c
+ ccnx_Interest.c
+ ccnx_InterestReturn.c
+ ccnx_InterestPayloadId.c
+ ccnx_KeyLocator.c
+ ccnx_KeystoreUtilities.c
+ ccnx_Link.c
+ ccnx_Manifest.c
+ ccnx_ManifestHashGroup.c
+ ccnx_Name.c
+ ccnx_NameSegment.c
+ ccnx_NameSegmentNumber.c
+ ccnx_NameLabel.c
+ ccnx_TimeStamp.c
+ ccnx_WireFormatMessage.c
+ )
+
+source_group(core FILES ${CORE_SRCS})
+
+set(ALL_SRCS
+ ${INTERNAL_SRCS}
+ ${VALIDATION_SRCS}
+ ${CORE_SRCS}
+ ${CODEC_SRCS}
+ ${VALIDATION_HDRS}
+ ${INTERNAL_HDRS}
+ ${CODEC_HDRS}
+ ${TESTDATA_HDRS}
+ ${SCHEMAV1_TESTDATA_HDRS}
+ ${SCHEMAV1_HDRS}
+ ${COMMON_HDRS}
+ )
+
+set(PUBLIC_HDRS
+ ${CODEC_PRIVATE_HDRS}
+)
+
+configure_file("config.h.in" "config.h" @ONLY)
+
+if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
+ set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS} -undefined dynamic_lookup")
+ message( "-- Set \"-undefined dynamic_lookup\" for shared libraries")
+endif()
+
+add_library(ccnx_common STATIC ${ALL_SRCS} ${ALL_HDRS})
+add_library(ccnx_common.shared SHARED ${ALL_SRCS})
+
+target_link_libraries(ccnx_common.shared ${LIBPARC_LIBRARIES})
+set_target_properties(ccnx_common.shared PROPERTIES
+ C_STANDARD 99
+ SOVERSION 1
+ VERSION 1.0
+ OUTPUT_NAME ccnx_common )
+
+set(libccnx_commonLibraries
+ ccnx_common
+ ccnx_common.shared
+ )
+
+foreach(lib ${libccnx_commonLibraries})
+ install(TARGETS ${lib} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
+ set_property(TARGET ${lib} PROPERTY C_STANDARD 99)
+endforeach()
+
+install(FILES ${CORE_HDRS} DESTINATION include/ccnx/common )
+install(FILES ${INTERNAL_HDRS} DESTINATION include/ccnx/common/internal )
+install(FILES ${VALIDATION_HDRS} DESTINATION include/ccnx/common/validation )
+install(FILES ${CODEC_HDRS} DESTINATION include/ccnx/common/codec )
+install(FILES ${TESTDATA_HDRS} DESTINATION include/ccnx/common/codec/testdata )
+install(FILES ${SCHEMAV1_HDRS} DESTINATION include/ccnx/common/codec/schema_v1 )
+install(FILES ${SCHEMAV1_TESTDATA_HDRS} DESTINATION include/ccnx/common/codec/schema_v1/testdata )
+
+#add_subdirectory(test)
+#add_subdirectory(validation/test)
+#add_subdirectory(codec/test)
+#add_subdirectory(internal/test)
+#add_subdirectory(codec/schema_v1/test)
diff --git a/libccnx-common/ccnx/common/Groups.dox b/libccnx-common/ccnx/common/Groups.dox
new file mode 100644
index 00000000..8f3dec80
--- /dev/null
+++ b/libccnx-common/ccnx/common/Groups.dox
@@ -0,0 +1,16 @@
+/**
+@defgroup Naming CCN Naming
+@brief CCN Naming
+
+@defgroup Interest CCN Interest
+@brief Functions to manipulate CCN Interest instances
+
+@defgroup ContentObject CCN Content Object
+@brief Functions to manipulate CCN Content Object instances.
+
+@defgroup Signature Signatures and Keys
+@brief Functions to manipulate Signatures and Keys.
+
+@defgroup Utility General Purpose functionality.
+@brief General purpose utility objects and functionality.
+*/
diff --git a/libccnx-common/ccnx/common/ccnx_ContentObject.c b/libccnx-common/ccnx/common/ccnx_ContentObject.c
new file mode 100644
index 00000000..b7367da9
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_ContentObject.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/internal/ccnx_ContentObjectInterface.h>
+
+#include <ccnx/common/ccnx_ContentObject.h>
+
+#include <ccnx/common/validation/ccnxValidation_HmacSha256.h>
+#include <ccnx/common/validation/ccnxValidation_RsaSha256.h>
+
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+
+static const CCNxContentObjectInterface *_defaultImplementation = &CCNxContentObjectFacadeV1_Implementation;
+
+/**
+ * A CCNxContentObject is a wrapper class providing a consistent interface for applications.
+ * Internally, the data of a ContentObject is stored in the underlying ccnxTlvDictionary.
+ * Because we may have different schemas for a ContentObject, an CCNxContentObjectInterface pointer
+ * is also stored in the underlying ccnxTlvDictionary. This provides access to the functions
+ * used to create and access a particular implementation of a ContentObject.
+ */
+
+CCNxContentObject *
+ccnxContentObject_CreateWithNameAndPayload(const CCNxName *contentName, const PARCBuffer *payload)
+{
+ return ccnxContentObject_CreateWithImplAndPayload(_defaultImplementation,
+ contentName,
+ CCNxPayloadType_DATA,
+ payload);
+}
+
+CCNxContentObject *
+ccnxContentObject_CreateWithPayload(const PARCBuffer *payload)
+{
+ return ccnxContentObject_CreateWithImplAndPayload(_defaultImplementation,
+ NULL,
+ CCNxPayloadType_DATA,
+ payload);
+}
+
+CCNxContentObject *
+ccnxContentObject_CreateWithImplAndPayload(const CCNxContentObjectInterface *impl,
+ const CCNxName *contentName,
+ const CCNxPayloadType payloadType,
+ const PARCBuffer *payload)
+{
+ CCNxContentObject *result = NULL;
+
+ if (impl->createWithNameAndPayload != NULL) {
+ if (contentName == NULL) {
+ result = impl->createWithPayload(payloadType, payload);
+ } else {
+ result = impl->createWithNameAndPayload(contentName, payloadType, payload);
+ }
+
+ // And set the dictionary's interface pointer to the one we just used to create this.
+ ccnxTlvDictionary_SetMessageInterface(result, impl);
+ } else {
+ trapNotImplemented("ContentObject implementations must implement createWithNameAndPayload()");
+ }
+
+ ccnxContentObject_SetPathLabel(result, 0);
+
+ return result;
+}
+
+bool
+ccnxContentObject_SetSignature(CCNxContentObject *contentObject, const PARCBuffer *keyId,
+ const PARCSignature *signature, const CCNxKeyLocator *keyLocator)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ bool result = false;
+
+ if (impl->setSignature != NULL) {
+ result = impl->setSignature(contentObject, keyId, signature, keyLocator);
+ }
+
+ return result;
+}
+
+PARCBuffer *
+ccnxContentObject_GetKeyId(const CCNxContentObject *contentObject)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+
+ PARCBuffer *result = NULL;
+
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+ if (impl->getKeyId != NULL) {
+ result = impl->getKeyId(contentObject);
+ }
+
+ return result;
+}
+
+CCNxName *
+ccnxContentObject_GetName(const CCNxContentObject *contentObject)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ CCNxName *result = NULL;
+
+ if (impl->getName != NULL) {
+ result = impl->getName(contentObject);
+ } else {
+ trapNotImplemented("ccnxContentObject_GetName");
+ }
+
+ return result;
+}
+
+PARCBuffer *
+ccnxContentObject_GetPayload(const CCNxContentObject *contentObject)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ PARCBuffer *result = NULL;
+
+ if (impl->getPayload != NULL) {
+ result = impl->getPayload(contentObject);
+ } else {
+ trapNotImplemented("ccnxContentObject_GetPayload");
+ }
+
+ return result;
+}
+
+CCNxPayloadType
+ccnxContentObject_GetPayloadType(const CCNxContentObject *contentObject)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ CCNxPayloadType result = CCNxPayloadType_DATA;
+
+ if (impl->getPayloadType != NULL) {
+ result = impl->getPayloadType(contentObject);
+ } else {
+ trapNotImplemented("ccnxContentObject_GetPayloadType");
+ }
+
+ return result;
+}
+
+bool
+ccnxContentObject_SetPayload(CCNxContentObject *contentObject, CCNxPayloadType payloadType, const PARCBuffer *payload)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ bool result = false;;
+
+ if (impl->setPayload != NULL) {
+ result = impl->setPayload(contentObject, payloadType, payload);;
+ } else {
+ trapNotImplemented("ccnxContentObject_SetPayload");
+ }
+
+ return result;
+}
+
+bool
+ccnxContentObject_SetExpiryTime(CCNxContentObject *contentObject, const uint64_t expiryTIme)
+{
+ bool result = false;
+
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ if (impl->setExpiryTime != NULL) {
+ result = impl->setExpiryTime(contentObject, expiryTIme);
+ } else {
+ trapNotImplemented("ccnxContentObject_SetExpiryTime");
+ }
+ return result;
+}
+
+bool
+ccnxContentObject_HasExpiryTime(const CCNxContentObject *contentObject)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ bool result = false;
+
+ if (impl->hasExpiryTime != NULL) {
+ result = impl->hasExpiryTime(contentObject);
+ } else {
+ return false;
+ }
+
+ return result;
+}
+
+uint64_t
+ccnxContentObject_GetExpiryTime(const CCNxContentObject *contentObject)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ if (impl->hasExpiryTime != NULL && !impl->hasExpiryTime((CCNxTlvDictionary *) contentObject)) {
+ trapUnexpectedState("ContentObject has no ExpiryTime. Call HasExpiryTime() first.");
+ }
+
+ if (impl->getExpiryTime != NULL) {
+ return impl->getExpiryTime(contentObject);
+ } else {
+ trapNotImplemented("ccnxContentObject_HasExpiryTime");
+ }
+}
+
+
+uint64_t
+ccnxContentObject_GetPathLabel(const CCNxContentObject *contentObject)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ if (impl->hasPathLabel != NULL && !impl->hasPathLabel((CCNxTlvDictionary *) contentObject)) {
+ trapUnexpectedState("ContentObject has no PathLabel. Call HasPathLabel() first.");
+ }
+
+ if (impl->getPathLabel != NULL) {
+ return impl->getPathLabel(contentObject);
+ } else {
+ trapNotImplemented("ccnxContentObject_GetPathLabel");
+ }
+}
+
+bool
+ccnxContentObject_SetPathLabel(CCNxContentObject *contentObject, const uint64_t pathLabel)
+{
+ bool result = false;
+
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ if (impl->setPathLabel != NULL) {
+ result = impl->setPathLabel(contentObject, pathLabel);
+ } else {
+ trapNotImplemented("ccnxContentObject_SetPathLabel");
+ }
+ return result;
+}
+
+bool
+ccnxContentObject_HasPathLabel(const CCNxContentObject *contentObject)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ bool result = false;
+
+ if (impl->hasPathLabel != NULL) {
+ result = impl->hasPathLabel(contentObject);
+ } else {
+ return false;
+ }
+
+ return result;
+}
+
+bool
+ccnxContentObject_SetFinalChunkNumber(CCNxContentObject *contentObject, const uint64_t finalChunkNumber)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ bool result = false;
+
+ if (impl->setFinalChunkNumber != NULL) {
+ result = impl->setFinalChunkNumber(contentObject, finalChunkNumber);
+ } else {
+ trapNotImplemented("ccnxContentObject_SetFinalChunkNumber");
+ }
+ return result;
+}
+
+bool
+ccnxContentObject_HasFinalChunkNumber(const CCNxContentObject *contentObject)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ bool result = false;
+
+ if (impl->hasFinalChunkNumber != NULL) {
+ result = impl->hasFinalChunkNumber(contentObject);
+ } else {
+ trapNotImplemented("ccnxContentObject_HasFinalChunkNumber");
+ }
+
+ return result;
+}
+
+uint64_t
+ccnxContentObject_GetFinalChunkNumber(const CCNxContentObject *contentObject)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ if (impl->hasFinalChunkNumber != NULL && !impl->hasFinalChunkNumber((CCNxTlvDictionary *) contentObject)) {
+ trapUnexpectedState("ContentObject has no final chunk number. Call ccnxContentObject_HasFinalChunkNumber() first.");
+ }
+
+ if (impl->getFinalChunkNumber != NULL) {
+ return impl->getFinalChunkNumber(contentObject);
+ } else {
+ trapNotImplemented("ccnxContentObject_GetFinalChunkNumber");
+ }
+}
+
+void
+ccnxContentObject_Display(const CCNxContentObject *contentObject, int indentation)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ if (impl->display != NULL) {
+ impl->display(contentObject, indentation);
+ } else {
+ ccnxTlvDictionary_Display(contentObject, indentation);
+ }
+}
+
+char *
+ccnxContentObject_ToString(const CCNxContentObject *contentObject)
+{
+ ccnxContentObject_OptionalAssertValid(contentObject);
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ char *result = NULL;
+
+ if (impl->toString != NULL) {
+ result = impl->toString(contentObject);
+ } else {
+ trapNotImplemented("ccnxContentObject_ToString");
+ }
+ return result;
+}
+
+bool
+ccnxContentObject_Equals(const CCNxContentObject *objectA, const CCNxContentObject *objectB)
+{
+ CCNxContentObjectInterface *implA = ccnxContentObjectInterface_GetInterface(objectA);
+ CCNxContentObjectInterface *implB = ccnxContentObjectInterface_GetInterface(objectB);
+
+ assertNotNull(implA, "ContentObject must have an valid implementation pointer.");
+ assertNotNull(implB, "ContentObject must have an valid implementation pointer.");
+
+ if (implA != implB) {
+ return false;
+ }
+
+ if (implA->equals != NULL) {
+ return implA->equals(objectA, objectB);
+ } else {
+ trapNotImplemented("ccnxContentObject_Equals");
+ }
+}
+
+CCNxContentObject *
+ccnxContentObject_Acquire(const CCNxContentObject *contentObject)
+{
+ return ccnxTlvDictionary_Acquire(contentObject);
+}
+
+void
+ccnxContentObject_Release(CCNxContentObject **contentObjectP)
+{
+ ccnxTlvDictionary_Release(contentObjectP);
+}
+
+void
+ccnxContentObject_AssertValid(const CCNxContentObject *contentObject)
+{
+ assertNotNull(contentObject, "Parameter must be a non-null CCNxContentObject pointer");
+ CCNxContentObjectInterface *impl = ccnxContentObjectInterface_GetInterface(contentObject);
+
+ assertNotNull(impl, "ContentObject must have a non-NUll implementation");
+ if (impl->assertValid != NULL) {
+ impl->assertValid(contentObject);
+ }
+}
diff --git a/libccnx-common/ccnx/common/ccnx_ContentObject.h b/libccnx-common/ccnx/common/ccnx_ContentObject.h
new file mode 100755
index 00000000..bff92433
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_ContentObject.h
@@ -0,0 +1,677 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_ContentObject.h
+ * @brief A CCNx ContentObject contains content to be sent in response to an Interest.
+ *
+ * The canonical CCN content object. A content object contains a payload, a {@link CCNxName},
+ * and security binding information. It's sent in response to a CCN Interest.
+ *
+ * @see {@link CCNxInterest}
+ *
+ */
+
+#ifndef libccnx_ccnx_ContentObject_h
+#define libccnx_ccnx_ContentObject_h
+#include <stdbool.h>
+
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/common/ccnx_PayloadType.h>
+#include <ccnx/common/ccnx_KeyLocator.h>
+
+#include <ccnx/common/internal/ccnx_ContentObjectInterface.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+#include <parc/security/parc_Signature.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+/**
+ * @typedef CCNxContentObject
+ * @brief The CCNx Content Object
+ */
+typedef CCNxTlvDictionary CCNxContentObject;
+
+/**
+ * Create a new instance of a `CCNxContentObject`, using dynamically allocated memory, with
+ * the specified name and payload.
+ *
+ * The created instance must be released by calling {@link ccnxContentObject_Release()}.
+ *
+ * @param [in] contentName The CCNxName associated with this `CCNxContentObject`.
+ * @param [in] payload The data to be encapsulated by this `CCNxContentObject`. May be NULL.
+ *
+ * @return A new instance of a `CCNxContentObject`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ * PARCBuffer *payload = parcBuffer_Allocate(<...>);
+ *
+ * CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ *
+ * ccnxContentObject_Release(&contentObject);
+ * ccnxName_Release(&name);
+ * parcBuffer_Release(&payload);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxContentObject_Release}
+ */
+CCNxContentObject *ccnxContentObject_CreateWithNameAndPayload(const CCNxName *contentName,
+ const PARCBuffer *payload);
+
+/**
+ * Create a new instance of a `CCNxContentObject`, using dynamically allocated memory, with
+ * the specified payload. This will be a "nameless" Content Object.
+ *
+ * The created instance must be released by calling {@link ccnxContentObject_Release()}.
+ *
+ * @param [in] payload The data to be encapsulated by this `CCNxContentObject`. May be NULL.
+ *
+ * @return A new instance of a `CCNxContentObject`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ * PARCBuffer *payload = parcBuffer_Allocate(<...>);
+ *
+ * CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ *
+ * ccnxContentObject_Release(&contentObject);
+ * ccnxName_Release(&name);
+ * parcBuffer_Release(&payload);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxContentObject_Release}
+ */
+CCNxContentObject *ccnxContentObject_CreateWithPayload(const PARCBuffer *payload);
+
+/**
+ * Create a new instance of a `CCNxContentObject`, using dynamically allocated memory, with
+ * the specified payload, using the specified {@link CCNxContentObjectInterface}.
+ *
+ * The created instance must be released by calling {@link ccnxContentObject_Release}().
+ *
+ * @param [in] implementation The interface's underlying implementation to use to build this ContentObject.
+ * @param [in] contentName The CCNxName associated with this `CCNxContentObject`.
+ * @param [in] type the type of the payload. Must be a valid {@link CCNxPayloadType}.
+ * @param [in] payload The data to be encapsulated by this `CCNxContentObject`. May be NULL.
+ *
+ * @return A new instance of a `CCNxContentObject`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ * PARCBuffer *payload = parcBuffer_Allocate(<...>);
+ *
+ * CCNxContentObject *contentObject =
+ * ccnxContentObject_CreateWithImplAndPayload(&contentObjectImpl_Facade_V0,
+ * name,
+ * CCNxPayloadType_DATA,
+ * payload);
+ *
+ * ccnxContentObject_Release(&contentObject);
+ * ccnxName_Release(&name);
+ * parcBuffer_Release(&payload);
+ * }
+ * @endcode
+ *
+ * @see ccnxContentObject_Release
+ */
+CCNxContentObject *ccnxContentObject_CreateWithImplAndPayload(const CCNxContentObjectInterface *implementation,
+ const CCNxName *contentName,
+ const CCNxPayloadType type,
+ const PARCBuffer *payload);
+
+
+/**
+ * Return a pointer to the {@link CCNxName} associated with this `CCNxContentObject`.
+ *
+ * This is memory managed by the `CCNxContentObject` and does not have to be released separately
+ * unless {@link ccnxName_Acquire()} is called to acquire it.
+ *
+ * @param [in] contentObject An pointer to an instance of a `CCNxContentObject`.
+ *
+ * @return A pointer to the `CCNxName` associated with the specified `CCNxContentObject`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ * PARCBuffer *payload = parcBuffer_Allocate(<...>);
+ *
+ * CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ *
+ * CCNxName *pointerToName = ccnxContentObject_GetName(contentObject);
+ *
+ * ...
+ *
+ * ccnxContentObject_Release(&contentObject);
+ * ccnxName_Release(&name);
+ * parcBuffer_Release(&payload);
+ * }
+ * @endcode
+ *
+ * @see `CCNxName`
+ */
+CCNxName *ccnxContentObject_GetName(const CCNxContentObject *contentObject);
+
+/**
+ * Return a pointer to the payload associated with this `CCNxContentObject`.
+ *
+ * The returned pointer points to the {@link PARCBuffer} containing the `CCNxContentObject`'s payload.
+ * This is memory managed by the `CCNxContentObject` and does not have to be released separately
+ * unless {@link parcBuffer_Acquire()} is called to acquire it.
+ *
+ * @param [in] contentObject A pointer to an instance of a `CCNxContentObject`.
+ *
+ * @return A pointer to the `PARCBuffer` containing the specified `CCNxContentObject`'s payload.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ * PARCBuffer *payload = parcBuffer_Allocate(<...>);
+ *
+ * CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ *
+ * CCNxName *pointerToPayload = ccnxContentObject_GetPayload(contentObject);
+ *
+ * ...
+ *
+ * ccnxContentObject_Release(&contentObject);
+ * ccnxName_Release(&name);
+ * parcBuffer_Release(&payload);
+ * }
+ * @endcode
+ *
+ * @see `PARCBuffer`
+ */
+PARCBuffer *ccnxContentObject_GetPayload(const CCNxContentObject *contentObject);
+
+/**
+ * Return the type of payload for this `CCNxContentObject`.
+ *
+ * The enumeration must be one of the defined values in {@link CCNxPayloadType}.
+ *
+ * @param [in] contentObject A pointer to an instance of a `CCNxContentObject`.
+ *
+ * @return The `CCNxContentObject` instances payload type.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ * PARCBuffer *payload = parcBuffer_Allocate(<...>);
+ *
+ * CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ *
+ * ...
+ *
+ * CCNxPayloadType payloadType = ccnxContentObject_GetPayloadType(contentObject);
+ * if (payloadType == CCNx_PAYLOAD_DATA) {
+ * printf("Payload type is CCNx_PAYLOAD_DATA (raw data)");
+ * }
+ *
+ * ...
+ *
+ * ccnxContentObject_Release(&contentObject);
+ * ccnxName_Release(&name);
+ * parcBuffer_Release(&payload);
+ * }
+ * @endcode
+ */
+CCNxPayloadType ccnxContentObject_GetPayloadType(const CCNxContentObject *contentObject);
+
+/**
+ * Set the number of the final chunk necessary to represent the content
+ * in this ContentObject.
+ *
+ * The final chunk number is the 0-based count of the last chunk necessary
+ * to encapsulate the content in this ContentObject. For example, if it would
+ * take 10 chunks to encapsulate some content, the final chunk number would be 9.
+ *
+ * @param [in,out] contentObject A pointer to the `CCNxContentObject` to which to assign the final chunk number.
+ * @param [in] finalChunkNumber The number of the final chunk
+ *
+ * @return `true` If the final chunk number was succesfully set.
+ * @return `false` If the final chunk number could not be set. This might happen if the
+ * underlying transport format doesn't support final chunk numbers.
+ * Example:
+ * @code
+ * {
+ * uint64_t finalChunkNumber = 2803;
+ * ccnxContentObject_SetFinalChunkNumber(contentObject, finalChunkNumber);
+ * }
+ * @endcode
+ *
+ * @see ccnxContentObject_GetFinalChunkNumber
+ */
+bool ccnxContentObject_SetFinalChunkNumber(CCNxContentObject *contentObject, const uint64_t finalChunkNumber);
+
+/**
+ * Returns `true` if this `CCNxContentObject` has a final chunk number.
+ *
+ * @param [in] contentObject A pointer to the `CCNxContentObject`
+ *
+ * @return `true` If the object has a final chunk number set.
+ * @return `false` If the object has no final chunk number set.
+ *
+ * Example:
+ * @code
+ * {
+ * if (ccnxContentObject_HasFinalChunkNumber(contentObject)) {
+ * uint64_t finalChunkNumber = ccnxContentObject_GetFinalChunkNumber(contentObject);
+ * ...
+ * }
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxContentObject_GetFinalChunkNumber}
+ */
+bool ccnxContentObject_HasFinalChunkNumber(const CCNxContentObject *contentObject);
+
+/**
+ * Return the final chunk number specified by this `CCNxContentObject`.
+ *
+ * @param [in] contentObject A pointer to the `CCNxContentObject` to get the final chunk number from.
+ *
+ * @return The final chunk number of the specified `CCNxContentObject`.
+ *
+ * Example:
+ * @code
+ * {
+ * uint64_t finalChunkNumber = ccnxContentObject_SetFinalChunkNumber(contentObject);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxContentObject_SetFinalChunkNumber}
+ */
+uint64_t ccnxContentObject_GetFinalChunkNumber(const CCNxContentObject *contentObject);
+
+/**
+ * Associate the supplied keyId, signature, and keyLocator with the specified `CCNxContentObject`.
+ *
+ * @param [in,out] contentObject A pointer to the `CCNxContentObject` to update.
+ * @param [in] keyId A pointer to the {@link PARCBuffer} containing the keyId to assign to the contentObject.
+ * @param [in] signature A pointer to a {@link PARCSignature} to assign to the contentObject.
+ * @param [in] keyLocator A pointer to a {@link CCNxKeyLocator} to assign to the contentObject. May be NULL.
+ *
+ * @return true if the signature payload was successfully set, false otherwise.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/hello/dolly");
+ * PARCBuffer *payload = parcBuffer_WrapCString("hello");
+ *
+ * CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ *
+ * PARCBuffer *keyId = parcBuffer_WrapCString("keyhash");
+ * PARCBuffer *sigbits = parcBuffer_CreateFromArray((void *) "siggybits", strlen("siggybits"));
+ * PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, parcBuffer_Flip(sigbits));
+ *
+ * ccnxContentObject_SetSignature(contentObject, keyId, signature, NULL);
+ *
+ * parcBuffer_Release(&payload);
+ * parcBuffer_Release(&sigbits);
+ * parcBuffer_Release(&keyId);
+ * parcSignature_Release(&signature);
+ * ccnxName_Release(&name);
+ * ccnxContentObject_Release(&contentObject);
+ * }
+ * @endcode
+ *
+ * @see `PARCSignature`
+ * @see `CCNxKeyLocator`
+ * @see `PARCBuffer`
+ */
+bool ccnxContentObject_SetSignature(CCNxContentObject *contentObject, const PARCBuffer *keyId,
+ const PARCSignature *signature, const CCNxKeyLocator *keyLocator);
+
+
+/**
+ * Get the associated keyId from the specified `CCNxContentObject`.
+ *
+ * @param [in] contentObject A pointer to the `CCNxContentObject`.
+ *
+ * @return PARCBuffer A PARCBuffer containing the keyId or NULL if there is no keyId associated with the object.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *keyId = ccnxContentObject_GetKeyId(contentObject);
+ * if (keyId != NULL) {
+ * ...
+ * }
+ * }
+ * @endcode
+ *
+ * @see `ccnxContentObject_SetSignature`
+ */
+PARCBuffer *ccnxContentObject_GetKeyId(const CCNxContentObject *contentObject);
+
+/**
+ * Increase the number of references to a `CCNxContentObject`.
+ *
+ * Note that a new `CCNxContentObject` is not created,
+ * only that the given `CCNxContentObject` reference count is incremented.
+ * Discard the reference by invoking {@link ccnxContentObject_Release}.
+ *
+ * @param [in] contentObject A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * CCNxContentObject *reference = ccnxContentObject_Acquire(contentObject);
+ *
+ * ...
+ *
+ * ccnxContentObject_Release(&reference);
+ *
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxContentObject_Release}
+ */
+CCNxContentObject *ccnxContentObject_Acquire(const CCNxContentObject *contentObject);
+
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] contentObjectP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxContentObject *reference = ccnxContentObject_Acquire(contentObject);
+ *
+ * ...
+ *
+ * ccnxContentObject_Release(&reference);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxContentObject_Acquire}
+ */
+void ccnxContentObject_Release(CCNxContentObject **contentObjectP);
+
+#ifdef Libccnx_DISABLE_VALIDATION
+# define ccnxContentObject_OptionalAssertValid(_instance_)
+#else
+# define ccnxContentObject_OptionalAssertValid(_instance_) ccnxContentObject_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that an instance of `CCNxContentObject` is valid.
+ *
+ * If the instance is not valid, terminate via {@link trapIllegalValue}
+ *
+ * Valid means the internal state of the type is consistent with its
+ * required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] contentObject A pointer to the instance to check.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ * PARCBuffer *payload = parcBuffer_Allocate(<...>);
+ *
+ * CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ *
+ * ccnxContentObject_AssertValid(contentObject);
+ *
+ * ccnxContentObject_Release(&contentObject);
+ * ccnxName_Release(&name);
+ * parcBuffer_Release(&payload);
+ * }
+ * @endcode
+ */
+void ccnxContentObject_AssertValid(const CCNxContentObject *contentObject);
+
+/**
+ * Produce a null-terminated C-string representation of the specified instance.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to the instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A null-terminated string that must be deallocated via `parcMemory_Deallocate`.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * char *stringRep = ccnxContentObject_ToString(contentObject);
+ * parcMemory_Deallocate(&stringRep);
+ * }
+ * @endcode
+ * @see `parcMemory_Deallocate`
+ */
+char *ccnxContentObject_ToString(const CCNxContentObject *contentObject);
+
+/**
+ * Determine if two `CCNxContentObject` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxContentObject` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `ccnxContentObject_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `ccnxContentObject_Equals(x, y)` must return true if and only if
+ * `ccnxContentObject_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxContentObject_Equals(x, y)` returns true and
+ * `ccnxContentObject_Equals(y, z)` returns true,
+ * then `ccnxContentObject_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `ccnxContentObject_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxContentObject_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param objectA A pointer to a `CCNxContentObject` instance.
+ * @param objectB A pointer to a `CCNxContentObject` instance.
+ * @return true if the two `CCNxContentObject` instances are equal.
+ *
+ * Example:
+ * @code
+ * @endcode
+ */
+bool ccnxContentObject_Equals(const CCNxContentObject *objectA, const CCNxContentObject *objectB);
+
+/**
+ * Get the ExpiryTime of the specified `ContentObject` instance.
+ *
+ * The ExpiryTime is the time at which the Payload expires, as expressed by a timestamp containing the number of
+ * milliseconds since the epoch in UTC. A cache or end system should not respond with a Content Object past its
+ * ExpiryTime. Routers forwarding a Content Object do not need to check the ExpiryTime. If the ExpiryTime field
+ * is missing, the Content Object has no expressed expiration and a cache or end system may use the Content
+ * Object for as long as it desires.
+ *
+ * Note: Calling this method on a `CCNxContentObject` that has no expiry time will cause a trap. Before calling,
+ * check that an ExpiryTime exists by calling {@link ccnxContentObject_HasExpiryTime} first.
+ *
+ * @param [in] instance A pointer to a `CCNxContentObject` instance.
+ *
+ * @return the ExpiryTime of the specified ContentObject.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxContentObject *contentObject = ccnxContentObject_Create<...>;
+ *
+ * if (ccnxContentObject_HasExpiryTime(contentObject) {
+ * uint64_t expiryTime = ccnxContentObject_GetExpiryTime(contentObject);
+ * } else {
+ * ccnxContentObject_SetExpiryTime(contentObject, 1478188800000ULL);
+ * }
+ * }
+ * @endcode
+ * @see `ccnxContentObject_HasExpiryTime`
+ * @see `ccnxContentObject_SetExpiryTime`
+ */
+uint64_t ccnxContentObject_GetExpiryTime(const CCNxContentObject *contentObject);
+
+/**
+ * Set the ExpiryTime of the specified `ContentObject` instance.
+ *
+ * See {@link ccnxContentObject_GetExpiryTime} for a description of ExpiryTime.
+ *
+ * @param [in] instance A pointer to the `CCNxContentObject` instance to be updated.
+ * @param [in] expiryTime The ExpiryTime to set.
+ *
+ * @return true, if the ExpiryTime was succesfully set.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxContentObject *contentObject = ccnxContentObject_Create<...>;
+ *
+ * if (ccnxContentObject_HasExpiryTime(contentObject) {
+ * uint64_t expiryTime = ccnxContentObject_GetExpiryTime(contentObject);
+ * } else {
+ * ccnxContentObject_SetExpiryTime(contentObject, 1478188800000ULL);
+ * }
+ * }
+ * @endcode
+ * @see `ccnxContentObject_GetExpiryTime`
+ * @see `ccnxContentObject_HasExpiryTime`
+ */
+bool ccnxContentObject_SetExpiryTime(CCNxContentObject *contentObject, const uint64_t expiryTime);
+
+/**
+ * Test whether the specified `ContentObject` instance has an ExpiryTime set.
+ *
+ * See {@link ccnxContentObject_GetExpiryTime} for a description of ExpiryTime.
+ *
+ * @param [in] instance A pointer to the `CCNxContentObject` instance to be updated.
+ *
+ * @return true, if the specified `CCNxContentObject` has an ExpiryTime.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxContentObject *contentObject = ccnxContentObject_Create<...>;
+ *
+ * if (ccnxContentObject_HasExpiryTime(contentObject) {
+ * uint64_t expiryTime = ccnxContentObject_GetExpiryTime(contentObject);
+ * } else {
+ * ccnxContentObject_SetExpiryTime(contentObject, 1478188800000ULL);
+ * }
+ * }
+ * @endcode
+ * @see `ccnxContentObject_GetExpiryTime`
+ * @see `ccnxContentObject_SetExpiryTime`
+ */
+bool ccnxContentObject_HasExpiryTime(const CCNxContentObject *contentObject);
+
+uint64_t ccnxContentObject_GetPathLabel(const CCNxContentObject *contentObject);
+bool ccnxContentObject_SetPathLabel(CCNxContentObject *contentObject, const uint64_t pathLabel);
+bool ccnxContentObject_HasPathLabel(const CCNxContentObject *contentObject);
+
+/**
+ * Set a payload on the specified `CCnxContentObject` instance.
+ *
+ * Currently, a payload may only be set once on a `CCnxContentObject` once, and may not be replaced.
+ *
+ * @param [in] contentObject A pointer to the `CCNxContentObject` instance to be updated.
+ * @param [in] payloadType The type of payload. See {@link CCNxPayloadType} for available types.
+ * @param [in] payload A pointer to the {@link PARCBuffer} to assign as the payload..
+ *
+ * @return true, if the payload was successfully added to the specified `CCNxContentObject`
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ * PARCBuffer *payload = parcBuffer_Allocate(<...>);
+ *
+ * CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, NULL);
+ *
+ * CCNxName *pointerToPayload = ccnxContentObject_GetPayload(contentObject);
+ * if (pointerToPayload == NULL) {
+ * ccnxContentObject_SetPayload(contentObject, CCNxPayloadType_DATA, payload);
+ * }
+ *
+ * ...
+ *
+ * ccnxContentObject_Release(&contentObject);
+ * ccnxName_Release(&name);
+ * parcBuffer_Release(&payload);
+ * }
+ * @endcode
+ * @see `CCNxPayloadType`
+ * @see `PARCBuffer`
+ * @see `ccnxContentObject_GetPayload`
+ */
+bool ccnxContentObject_SetPayload(CCNxContentObject *contentObject, CCNxPayloadType payloadType, const PARCBuffer *payload);
+
+/**
+ * Get the {@link CCNxPayloadType} of the specified `CCnxContentObject` instance.
+ *
+ * @param [in] instance A pointer to the `CCNxContentObject` instance to be updated.
+ *
+ * @return true, if the payload was successfully added to the specified `CCNxContentObject`
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ * PARCBuffer *payload = parcBuffer_Allocate(<...>);
+ *
+ * CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, NULL);
+ *
+ * CCNxName *pointerToPayload = ccnxContentObject_GetPayload(contentObject);
+ * if (pointerToPayload == NULL) {
+ * ccnxContentObject_SetPayload(contentObject, CCNxPayloadType_DATA, payload);
+ * }
+ *
+ * ...
+ *
+ * ccnxContentObject_Release(&contentObject);
+ * ccnxName_Release(&name);
+ * parcBuffer_Release(&payload);
+ * }
+ * @endcode
+ * @see `CCNxPayloadType`
+ * @see `PARCBuffer`
+ * @see `ccnxContentObject_GetPayload`
+ */
+CCNxPayloadType ccnxContentObject_GetPayloadType(const CCNxContentObject *contentObject);
+#endif // libccnx_ccnx_ContentObject_h
diff --git a/libccnx-common/ccnx/common/ccnx_Interest.c b/libccnx-common/ccnx/common/ccnx_Interest.c
new file mode 100755
index 00000000..481be0bc
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_Interest.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/ccnx_Interest.h>
+
+#include <ccnx/common/internal/ccnx_InterestDefault.h>
+#include <ccnx/common/ccnx_InterestPayloadId.h>
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <stdio.h>
+
+static const CCNxInterestInterface *_defaultImplementation = &CCNxInterestFacadeV1_Implementation;
+
+CCNxInterest *
+ccnxInterest_Create(const CCNxName *name,
+ uint32_t lifetime,
+ const PARCBuffer *keyId,
+ const PARCBuffer *contentObjectHash)
+{
+ return ccnxInterest_CreateWithImpl(_defaultImplementation,
+ name,
+ lifetime,
+ keyId,
+ contentObjectHash,
+ CCNxInterestDefault_HopLimit);
+}
+
+CCNxInterest *
+ccnxInterest_CreateWithImpl(const CCNxInterestInterface *impl,
+ const CCNxName *name,
+ const uint32_t interestLifetime,
+ const PARCBuffer *keyId,
+ const PARCBuffer *contentObjectHash,
+ const uint32_t hopLimit)
+{
+ CCNxInterest *result = NULL;
+
+ if (impl->create != NULL) {
+ result = impl->create(name, interestLifetime, keyId, contentObjectHash, hopLimit);
+
+ // And set the dictionary's interface pointer to the one we just used to create this.
+ ccnxTlvDictionary_SetMessageInterface(result, impl);
+ } else {
+ trapNotImplemented("Interest implementations must implement create()");
+ }
+ return result;
+}
+
+
+CCNxInterest *
+ccnxInterest_CreateSimple(const CCNxName *name)
+{
+ return ccnxInterest_Create(name,
+ CCNxInterestDefault_LifetimeMilliseconds,
+ NULL,
+ NULL);
+}
+
+void
+ccnxInterest_AssertValid(const CCNxInterest *interest)
+{
+ assertNotNull(interest, "Must be a non-null pointer to a CCNxInterest.");
+
+ // Check for required fields in the underlying dictionary. Case 1036
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+ assertNotNull(impl, "Interest must have an valid implementation pointer.");
+
+ if (impl->assertValid != NULL) {
+ impl->assertValid(interest);
+ }
+}
+
+CCNxInterest *
+ccnxInterest_Acquire(const CCNxInterest *instance)
+{
+ return ccnxTlvDictionary_Acquire(instance);
+}
+
+void
+ccnxInterest_Release(CCNxInterest **instanceP)
+{
+ ccnxTlvDictionary_Release(instanceP);
+}
+
+bool
+ccnxInterest_Equals(const CCNxInterest *a, const CCNxInterest *b)
+{
+ if (a == b) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ CCNxInterestInterface *implA = ccnxInterestInterface_GetInterface(a);
+ CCNxInterestInterface *implB = ccnxInterestInterface_GetInterface(b);
+
+ if (implA != implB) {
+ return false;
+ }
+
+ CCNxName *nameA = implA->getName(a);
+ CCNxName *nameB = implB->getName(b);
+
+ PARCBuffer *keyA = implA->getKeyIdRestriction(a);
+ PARCBuffer *keyB = implB->getKeyIdRestriction(b);
+
+ uint64_t lifetimeA = implA->getLifetime(a);
+ uint64_t lifetimeB = implB->getLifetime(b);
+
+ if (ccnxName_Equals(nameA, nameB)) {
+ if (parcBuffer_Equals(keyA, keyB)) {
+ // Must compare the excludes.
+ if (lifetimeA == lifetimeB) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+CCNxName *
+ccnxInterest_GetName(const CCNxInterest *interest)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ CCNxName *result = NULL;
+
+ if (impl->getName != NULL) {
+ result = impl->getName(interest);
+ } else {
+ trapNotImplemented("ccnxInterest_GetName");
+ }
+ return result;
+}
+
+bool
+ccnxInterest_SetContentObjectHashRestriction(CCNxInterest *interest, const PARCBuffer *contentObjectHash)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ bool result = false;
+
+ if (impl->setContentObjectHashRestriction != NULL) {
+ result = impl->setContentObjectHashRestriction(interest, contentObjectHash);
+ } else {
+ trapNotImplemented("ccnxInterest_SetContentObjectHashRestriction");
+ }
+ return result;
+}
+
+PARCBuffer *
+ccnxInterest_GetContentObjectHashRestriction(const CCNxInterest *interest)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ PARCBuffer *result = NULL;
+
+ if (impl->getContentObjectHashRestriction != NULL) {
+ result = impl->getContentObjectHashRestriction(interest);
+ } else {
+ trapNotImplemented("ccnxInterest_GetContentObjectHash");
+ }
+ return result;
+}
+
+bool
+ccnxInterest_SetKeyIdRestriction(CCNxInterest *interest, const PARCBuffer *keyId)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ bool result = false;
+
+ if (impl->setKeyIdRestriction != NULL) {
+ result = impl->setKeyIdRestriction(interest, keyId);
+ } else {
+ trapNotImplemented("ccnxInterest_SetKeyIdRestriction");
+ }
+ return result;
+}
+
+PARCBuffer *
+ccnxInterest_GetKeyIdRestriction(const CCNxInterest *interest)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ PARCBuffer *result = NULL;
+
+ if (impl->getKeyIdRestriction != NULL) {
+ result = impl->getKeyIdRestriction(interest);
+ } else {
+ trapNotImplemented("ccnxInterest_GetKeyIdRestriction");
+ }
+ return result;
+}
+
+bool
+ccnxInterest_SetLifetime(CCNxInterest *interest, uint32_t lifetime)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ bool result = false;
+
+ if (impl->setLifetime != NULL) {
+ result = impl->setLifetime(interest, lifetime);
+ } else {
+ trapNotImplemented("ccnxInterest_SetLifetime");
+ }
+ return result;
+}
+
+uint32_t
+ccnxInterest_GetLifetime(const CCNxInterest *interest)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ uint32_t result = 0;
+
+ if (impl->getLifetime != NULL) {
+ result = impl->getLifetime(interest);
+ } else {
+ trapNotImplemented("ccnxInterest_GetLifetime");
+ }
+ return result;
+}
+
+bool
+ccnxInterest_SetPayload(CCNxInterest *interest, const PARCBuffer *payload)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ bool result = false;
+
+ if (impl->setPayload != NULL) {
+ result = impl->setPayload(interest, payload);
+ } else {
+ trapNotImplemented("ccnxInterest_SetPayload");
+ }
+ return result;
+}
+
+bool
+ccnxInterest_SetPayloadAndId(CCNxInterest *interest, const PARCBuffer *payload)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ bool result = false;
+
+ if (impl->setPayloadAndId != NULL) {
+ result = impl->setPayloadAndId(interest, payload);
+ } else {
+ trapNotImplemented("ccnxInterest_SetPayloadAndId");
+ }
+ return result;
+}
+
+bool
+ccnxInterest_SetPayloadWithId(CCNxInterest *interest, const PARCBuffer *payload, const CCNxInterestPayloadId *payloadId)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ bool result = false;
+
+ if (impl->setPayloadWithId != NULL) {
+ result = impl->setPayloadWithId(interest, payload, payloadId);
+ } else {
+ trapNotImplemented("ccnxInterest_SetPayloadWithId");
+ }
+ return result;
+}
+
+PARCBuffer *
+ccnxInterest_GetPayload(const CCNxInterest *interest)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ PARCBuffer *result = NULL;
+
+ if (impl->getPayload != NULL) {
+ result = impl->getPayload(interest);
+ } else {
+ trapNotImplemented("ccnxInterest_GetPayload");
+ }
+ return result;
+}
+
+bool
+ccnxInterest_SetHopLimit(CCNxTlvDictionary *interest, uint32_t hopLimit)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ bool result = false;
+
+ if (impl->setHopLimit != NULL) {
+ result = impl->setHopLimit(interest, hopLimit);
+ } else {
+ trapNotImplemented("ccnxInterest_GetSetHopLimit");
+ }
+ // Make sure any attached wire format buffers are in sync with the dictionary
+ ccnxWireFormatMessage_SetHopLimit(interest, hopLimit);
+ return result;
+}
+
+uint32_t
+ccnxInterest_GetHopLimit(const CCNxTlvDictionary *interest)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ uint32_t result = 0;
+
+ if (impl->getHopLimit != NULL) {
+ result = impl->getHopLimit(interest);
+ } else {
+ trapNotImplemented("ccnxInterest_GetHopLimit");
+ }
+ return result;
+}
+
+void
+ccnxInterest_Display(const CCNxInterest *interest, int indentation)
+{
+ ccnxInterest_OptionalAssertValid(interest);
+
+ parcDisplayIndented_PrintLine(indentation, "CCNxInterest@%p {\n", interest);
+ ccnxName_Display(ccnxInterest_GetName(interest), indentation + 1);
+
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ if (impl->display != NULL) {
+ impl->display(interest, 1);
+ }
+
+ parcDisplayIndented_PrintLine(indentation, "}\n");
+}
+
+char *
+ccnxInterest_ToString(const CCNxInterest *interest)
+{
+ char *result = NULL;
+
+ ccnxInterest_OptionalAssertValid(interest);
+
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ if (impl->toString != NULL) {
+ result = impl->toString(interest);
+ } else {
+ char *name = ccnxName_ToString(ccnxInterest_GetName(interest));
+ uint32_t lifetime = ccnxInterest_GetLifetime(interest);
+
+ char *string;
+ int failure = asprintf(&string, "CCNxInterest{.name=\"%s\" .lifetime=%dms}", name, lifetime);
+ assertTrue(failure > 0, "Error from asprintf");
+
+ parcMemory_Deallocate((void **) &name);
+
+ result = parcMemory_StringDuplicate(string, strlen(string));
+
+ free(string);
+ }
+
+ return result;
+}
diff --git a/libccnx-common/ccnx/common/ccnx_Interest.h b/libccnx-common/ccnx/common/ccnx_Interest.h
new file mode 100755
index 00000000..20dd5c53
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_Interest.h
@@ -0,0 +1,807 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_Interest.h
+ * @ingroup Interest
+ * @brief A CCNx Interest expresses an interest in a piece of named data.
+ *
+ * The canonical CCN Interest. An Interest contains a {@link CCNxName},
+ * the desired payload, and two optional restrictions (ContentObjectHash and
+ * KeyId) to limit responses
+ * to a specific publisher or a specific Content Object.
+ *
+ * @see {@link CCNxContentObject}
+ * @see {@link CCNxName}
+ *
+ */
+
+#ifndef libccnx_ccnx_Interest_h
+#define libccnx_ccnx_Interest_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/internal/ccnx_InterestInterface.h>
+
+/**
+ * @typedef CCNxInterest
+ * @brief The CCNx Interest Message
+ */
+
+typedef CCNxTlvDictionary CCNxInterest;
+
+/**
+ * Create a new instance of `CCNxInterest` for the specified name, with the specified lifetime and
+ * publisher's key digest, using the specified {@link CCNxInterestInterface}, using dynamically allocated memory.
+ *
+ * The name and key digest are used for matching against ContentObjects. If the specified key digest is NULL,
+ * this Interest will match against any ContentObject with the same name (regardless of whether the
+ * ContentObject has matching key digest). If the specified key digest is NOT NULL, then this Interest
+ * will match only against any ContentObject with both the same name and the same key digest. The key digest
+ * comparison test is a simple buffer comparison.
+ *
+ * The lifetime, specified in milliseconds, is a hint to the system how long the application is
+ * willing to wait for a response before it will re-send the same Interest. It is used by forwarders as a
+ * guideline on how long they should attempt to keep the Interest alive in their tables. It is not a guarantee
+ * that they will do so, however.
+ *
+ * The created instance of `CCNxInterest` must be released by calling {@link ccnxInterest_Release}().
+ *
+ * @param [in] implementation A pointer to the {@link CCNxInterestInterface} to be used to build this Interest.
+ * @param [in] name A pointer to a {@link CCNxName} expressing the name of the content you are interested in.
+ * @param [in] lifetime A `uint32_t` specifying the number of milliseconds the application
+ * will wait before re-sending the Interest.
+ * @param [in] keyId A pointer to a {@link PARCBuffer} containing a key digest that should be matched
+ * against ContentObjects whose names match our specified name. This value may be NULL and, if so, will
+ * not be used in the matching process.
+ * @param [in] contentObjectHash A pointer to a `PARCBuffer` containing the hash of the ContentObject that is expected
+ * to be returned in response to this Interest.
+ *
+ * @return A new instance of a `CCNxInterest`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/temp/2");
+ *
+ * PARCBuffer *keyId = parcBuffer_Allocate(8);
+ * parcBuffer_PutUint64(keyId, 1234L);
+ *
+ * uint32_t lifetime = CCNxInterestDefaultLifetimeMilliseconds;
+ *
+ * CCNxInterest *interest = ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ * name, lifetime, keyId, NULL);
+ *
+ * ...
+ *
+ * parcBuffer_Release(&keyId);
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&interest);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterest_Release}
+ */
+CCNxInterest *ccnxInterest_CreateWithImpl(const CCNxInterestInterface *implementation,
+ const CCNxName *name,
+ const uint32_t interestLifetime,
+ const PARCBuffer *keyId,
+ const PARCBuffer *contentObjectHash,
+ const uint32_t hopLimit);
+
+/**
+ * Create a new instance of `CCNxInterest` for the specified name, with the specified lifetime and
+ * publisher's key digest, using dynamically allocated memory.
+ *
+ * The name and key digest are used for matching against ContentObjects. If the specified key digest is NULL,
+ * this Interest will match against any ContentObject with the same name (regardless of whether the
+ * ContentObject has matching key digest). If the specified key digest is NOT NULL, then this Interest
+ * will match only against any ContentObject with both the same name and the same key digest. The key digest
+ * comparison test is a simple buffer comparison.
+ *
+ * The lifetime, specified in milliseconds, is a hint to the system how long the application is
+ * willing to wait for a response before it will re-send the same Interest. It is used by forwarders as a
+ * guideline on how long they should attempt to keep the Interest alive in their tables. It is not a guarantee
+ * that they will do so, however.
+ *
+ * The created instance of `CCNxInterest` must be released by calling {@link ccnxInterest_Release}().
+ *
+ * @param [in] name A pointer to a {@link CCNxName} expressing the name of the content you are interested in.
+ * @param [in] lifetime A `uint32_t` specifying the number of milliseconds the application
+ * will wait before re-sending the Interest.
+ * @param [in] keyId A pointer to a {@link PARCBuffer} containing a key digest that should be matched
+ * against ContentObjects whose names match our specified name. This value may be NULL and, if so, will
+ * not be used in the matching process.
+ * @param [in] contentObjectHash A pointer to a `PARCBuffer` containing the hash of the ContentObject that is expected
+ * to be returned in response to this Interest.
+ *
+ * @return A new instance of a `CCNxInterest`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/temp/2");
+ *
+ * PARCBuffer *keyId = parcBuffer_Allocate(8);
+ * parcBuffer_PutUint64(keyId, 1234L);
+ *
+ * uint32_t lifetime = CCNxInterestDefaultLifetimeMilliseconds;
+ *
+ * CCNxInterest *interest = ccnxInterest_Create(name, lifetime, keyId, NULL);
+ *
+ * ...
+ *
+ * parcBuffer_Release(&keyId);
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&interest);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterest_Release}
+ */
+CCNxInterest *ccnxInterest_Create(const CCNxName *name,
+ uint32_t lifetime,
+ const PARCBuffer *keyId,
+ const PARCBuffer *contentObjectHash);
+
+
+/**
+ * Create a new instance of `CCNxInterest` for the specified name, using dynamically allocated memory.
+ *
+ * The created instance will specify a default lifetime, and will not specify a publisher's key
+ * digest for matching. Only the specified name will be used for matching. To specify values
+ * for the lifetime or publisher's key digest, see {@link ccnxInterest_Create()}.
+ *
+ * The created instance of `CCNxInterest` must be released by calling {@link ccnxInterest_Release}.
+ *
+ * @param [in] name A pointer to a `CCNxName` expressing the name of the content you are interested in.
+ *
+ * @return A new instance of a `CCNxInterest'.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/humidity/4");
+ *
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * ...
+ *
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&interest);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterest_Create}
+ * @see {@link ccnxInterest_Release}
+ */
+CCNxInterest *ccnxInterest_CreateSimple(const CCNxName *name);
+
+/**
+ * Determine if two `CCNxInterest` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxInterest` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `ccnxInterest_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `ccnxInterest_Equals(x, y)` must return true if and only if
+ * `ccnxInterest_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxInterest_Equals(x, y)` returns true and
+ * `ccnxInterest_Equals(y, z)` returns true,
+ * then `ccnxInterest_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `ccnxInterest_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxInterest_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param interestA A pointer to a `CCNxInterest` instance.
+ * @param interestB A pointer to a `CCNxInterest` instance.
+ * @return true if the two `CCNxInterest` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/11");
+ * uint32_t lifetime = 15 * 1000; // 15 seconds, in milliseconds
+ *
+ * PARCBuffer *keyDigest1 = parcBuffer_Allocate(8);
+ * parcBuffer_PutUint64(keyDigest1, 1234L);
+ *
+ * PARCBuffer *keyDigest2 = parcBuffer_Allocate(8);
+ * parcBuffer_PutUint64(keyDigest2, 6789L); // different buffer contents than keyDigest1
+ *
+ * CCNxInterest *interestA = ccnxInterest_Create(name, lifetime, keyDigest1, NULL);
+ * CCNxInterest *interestB = ccnxInterest_Create(name, lifetime, keyDigest1, NULL); // same as A
+ *
+ * CCNxInterest *interestC = ccnxInterest_Create(name, lifetime, keyDigest2); // different key digest
+ *
+ * if (ccnxInterest_Equals(interestA, interestB)) {
+ * // this is expected...
+ * }
+ *
+ * if (ccnxInterest_Equals(interestA, interestC)) {
+ * // this is NOT expected
+ * }
+ *
+ * ...
+ *
+ * ccnxName_Release(&name);
+ * parcBuffer_Release(&keyDigest1);
+ * parcBuffer_Release(&keyDigest2);
+ * ccnxInterest_Release(&interestA);
+ * ccnxInterest_Release(&interestB);
+ * ccnxInterest_Release(&interestC);
+ * }
+ * @endcode
+ */
+bool ccnxInterest_Equals(const CCNxInterest *interestA, const CCNxInterest *interestB);
+
+/**
+ * Return a pointer to the {@link CCNxName} associated with the given `CCNxInterest`.
+ *
+ * The pointer points to memory managed by the `CCNxInterest` and does not have to
+ * be released unless {@link ccnxName_Acquire()} is called to acquire it.
+ *
+ * @param [in] interest A pointer to a `CCNxInterest` instance.
+ *
+ * @return A pointer to the CCNxName associated with the specified `CCNxInterest`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxInterest_GetName(interest);
+ * }
+ * @endcode
+ *
+ * @see {@link CCNxName}
+ */
+CCNxName *ccnxInterest_GetName(const CCNxInterest *interest);
+
+/**
+ * Assign a lifetime value to the specified `CCNxInterest`.
+ *
+ * The lifetime, specified in milliseconds, is a hint to the system how long the application is
+ * willing to wait for a response before it will re-send the same Interest. It is used by forwarders as a
+ * guideline on how long they should attempt to keep the Interest alive in their tables. It is not a guarantee
+ * that they will do so, however.
+ *
+ * @param [in] interest A pointer to a `CCNxInterest` instance.
+ * @param [in] lifetime A `uint32_t` containing the desired lifetime of this Interest, in milliseconds.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/media/Ab00se");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * uint32_t lifetime = 15 * 1000; // 15 seconds, in milliseconds
+ * ccnxInterest_SetLifetime(interest, lifetime);
+ *
+ * ...
+ *
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&interest);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterest_GetLifetime}
+ */
+bool ccnxInterest_SetLifetime(CCNxInterest *interest, uint32_t lifetime);
+
+/**
+ * Retrieve the specified `CCNxInterest`'s lifetime value as a uint32_t.
+ * @param [in] interest A pointer to a `CCNxInterest` instance.
+ *
+ * @return The lifetime, in milliseconds, specified for this `CCNxInterest`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/media/b00se");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * uint32_t lifetime = ccnxInterest_GetLifetime(interest);
+ * ...
+ *
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&interest);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterest_SetLifetime}
+ */
+uint32_t ccnxInterest_GetLifetime(const CCNxInterest *interest);
+
+/**
+ * Assign a key ID to the specified `CCNxInterest`.
+ *
+ * The key ID is used when matching this `CCNxInterest` to CCNx content. If a non-NULL
+ * key ID is specified in the `CCNxInterest`, then only content with a matching key
+ * digest will be matched. If the `CCNxInterest`'s key ID is NULL, then it is not used
+ * when matching against content.
+ *
+ * @param [in,out] interest A pointer to a `CCNxInterest` instance.
+ * @param [in] keyId A pointer to a {@link PARCBuffer} containing the desired key ID, or NULL.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/media/r00");
+ *
+ * PARCBuffer *keyId = parcBuffer_Allocate(8);
+ * parcBuffer_PutUint64(keyId, 1234L);
+ *
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * ccnxInterest_SetKeyIdRestriction(interest, keyId);
+ *
+ * ...
+ *
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&interest);
+ * parcBuffer_Release(&keyId);
+ * }
+ * @endcode
+ *
+ * @see ccnxInterest_GetKeyId
+ */
+bool ccnxInterest_SetKeyIdRestriction(CCNxInterest *interest, const PARCBuffer *keyId);
+
+/**
+ * Return a pointer to the {@link PARCBuffer} containing the publisher key digest associated with the given `CCNxInterest`.
+ *
+ * The pointer points to memory managed by the `CCNxInterest` and does not have to
+ * be released unless {@link parcBuffer_Acquire()} is called to acquire it.
+ *
+ * @param [in] interest A pointer to a `CCNxInterest` instance.
+ *
+ * @return A pointer to a PARCBuffer containing the `CCNxInterest`'s key ID.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/media/p1e");
+ *
+ * PARCBuffer *keyId = parcBuffer_Allocate(8);
+ * parcBuffer_PutUint64(keyId, 1234L);
+ * uint32_t lifetime = 5000;
+ *
+ * CCNxInterest *interest = ccnxInterest_Create(name, lifetime, keyId, NULL);
+ *
+ * PARCBuffer *keyIdP = ccnxInterest_GetKeyIdRestriction(interest);
+ *
+ * ...
+ *
+ * ccnxName_Release(&name);
+ * parcBuffer_Release(&keyId);
+ * ccnxInterest_Release(&interest);
+ * }
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterest_SetKeyId}
+ */
+PARCBuffer *ccnxInterest_GetKeyIdRestriction(const CCNxInterest *interest);
+
+/**
+ * Assign a `ContentObjectHash` to the specified `CCNxInterest`.
+ *
+ * The `ContentObjectHash` is used when performing an exact match against this `CCNxInterest` and
+ * the response CCNx content. If a non-NULL `ContentObjectHash` is specified in the `CCNxInterest`,
+ * then only content whose hash digest matches the specified value will match and be returned. If
+ * the `ContentObjectHash` field is NULL, this binary equality check is not used when checking a response
+ * Content Object.
+ *
+ * @param [in,out] interest A pointer to a `CCNxInterest` instance.
+ * @param [in] contentObjectHash A pointer to a {@link PARCBuffer} containing the desired ContentObjectHash, or NULL.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/media/r00");
+ *
+ * PARCBuffer *contentObjectHash = parcBuffer_Allocate(8);
+ * parcBuffer_PutUint64(contentObjectHashcontentObjectHash, 1234L);
+ *
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * ccnxInterest_SetContentObjectHashRestriction(interest, contentObjectHash);
+ *
+ * ...
+ *
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&interest);
+ * parcBuffer_Release(&contentObjectHash);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterest_GetContentObjectHash}
+ */
+bool ccnxInterest_SetContentObjectHashRestriction(CCNxInterest *interest, const PARCBuffer *contentObjectHash);
+
+/**
+ * Return a pointer to the {@link PARCBuffer} containing the `ContentObjectHash` associated with the given `CCNxInterest`.
+ *
+ * The pointer points to memory managed by the `CCNxInterest` and does not have to
+ * be released unless {@link parcBuffer_Acquire()} is called to acquire it.
+ *
+ * @param [in] interest A pointer to a `CCNxInterest` instance.
+ *
+ * @return A pointer to a `PARCBuffer` containing the `CCNxInterest`'s `ContentObjectHash`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/media/p1e");
+ *
+ * uint32_t lifetime = 3 * 1000; // milliseconds
+ *
+ * PARCBuffer *contentObjectHash = parcBuffer_Allocate(8);
+ * parcBuffer_PutUint64(contentObjectHash, 1234L);
+ *
+ *
+ * CCNxInterest *interest = ccnxInterest_Create(name, lifetime, NULL, contentObjectHash);
+ *
+ * PARCBuffer *contentObjectHashP = ccnxInterest_GetContentObjectHashRestriction(interest);
+ *
+ * ...
+ *
+ * ccnxName_Release(&name);
+ * parcBuffer_Release(&contentObjectHash);
+ * ccnxInterest_Release(&interest);
+ * }
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterest_SetContentObjectHash}
+ */
+PARCBuffer *ccnxInterest_GetContentObjectHashRestriction(const CCNxInterest *interest);
+
+/**
+ * Produce a null-terminated string representation of the specified instance.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate()}.
+ *
+ * @param [in] interest A pointer to the instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, nul-terminated C string that must be deallocated via `parcMemory_Deallocate()`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/11");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * char *string = ccnxInterest_ToString(interest);
+ *
+ * if (string != NULL) {
+ * printf("Interest looks like: %s\n", string);
+ * parcMemory_Deallocate(string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see ccnxInterest_Display
+ * @see parcMemory_Deallocate
+ */
+char *ccnxInterest_ToString(const CCNxInterest *interest);
+
+/**
+ * Print a human readable representation of the given `CCNxInterest`.
+ *
+ * @param [in] interest A pointer to the instance to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/11");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * ccnxInterest_Display(interest, 0);
+ *
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&instance);
+ * }
+ * @endcode
+ * */
+void ccnxInterest_Display(const CCNxInterest *interest, int indentation);
+
+/**
+ * Increase the number of references to a `CCNxInterest`.
+ *
+ * Note that a new `CCNxInterest` is not created,
+ * only that the given `CCNxInterest` reference count is incremented.
+ * Discard the reference by invoking {@link ccnxInterest_Release}.
+ *
+ * @param [in] instance A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterest *reference = ccnxInterest_Acquire(interest);
+ *
+ * ...
+ *
+ * ccnxInterest_Release(&reference);
+ *
+ * }
+ * @endcode
+ *
+ * @see ccnxInterest_Release
+ */
+CCNxInterest *ccnxInterest_Acquire(const CCNxInterest *instance);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instanceP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterest *reference = ccnxInterest_Acquire(contentObject);
+ *
+ * ...
+ *
+ * ccnxInterest_Release(&reference);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterest_Acquire}
+ */
+void ccnxInterest_Release(CCNxInterest **instanceP);
+
+#ifdef Libccnx_DISABLE_VALIDATION
+# define ccnxInterest_OptionalAssertValid(_instance_)
+#else
+# define ccnxInterest_OptionalAssertValid(_instance_) ccnxInterest_AssertValid(_instance_)
+#endif
+/**
+ * Assert that an instance of `CCNxInterest` is valid.
+ *
+ * If the instance is not valid, terminate via {@link trapIllegalValue}
+ *
+ * Valid means the internal state of the type is consistent with its
+ * required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] interest A pointer to the instance to check.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/11");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * ccnxInterest_AssertValid(interest);
+ *
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&instance);
+ * }
+ * @endcode
+ */
+void ccnxInterest_AssertValid(const CCNxInterest *interest);
+
+
+/**
+ * Set the payload on an `CCnxInterest` instance. A reference to the supplied payload is
+ * acquired by the Interest, so the caller may release the payload after setting it on
+ * the CCnxInterest. The payload type must be specified, and must be one of the types
+ * defined in {@link CCNxPayloadType}.
+ *
+ * This will not append a payloadId segment to the Interest's name. If you want to do that,
+ * see {@link ccnxInterest_SetPayloadAndId} and {@link ccnxInterest_SetPayloadWithId}.
+ *
+ * @param [in] interest A pointer to the `CCNxInstance` instance to update.
+ * @param [in] payload A pointer to the PARCBuffer payload to be applied to the `CCNxInterest`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/11");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * PARCBuffer *payload = parcBuffer_Allocate(8);
+ * parcBuffer_PutUint64(payload, 5432L);
+ *
+ * ccnxInterest_SetPayload(interest, payload);
+ *
+ * parcBuffer_Release(&payload);
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&instance);
+ * }
+ * @endcode
+ * @see `CCNxPayloadType`
+ */
+bool ccnxInterest_SetPayload(CCNxInterest *interest, const PARCBuffer *payload);
+
+/**
+ * Set the payload on an `CCnxInterest` instance. A reference to the supplied payload is
+ * acquired by the Interest, so the caller may release the payload after setting it on
+ * the CCnxInterest. The payload type must be specified, and must be one of the types
+ * defined in {@link CCNxPayloadType}.
+ *
+ * This will also generate and append a payloadId name segment to the interest name using a
+ * sha256 hash (the default) of the payload buffer. If you'd like to take responsibility
+ * for generating a payloadId, use {@link ccnxInterest_SetPayloadAndId} instead.
+ *
+ * @param [in] interest A pointer to the `CCNxInstance` instance to update.
+ * @param [in] payload A pointer to the PARCBuffer payload to be applied to the `CCNxInterest`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/11");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * PARCBuffer *payload = parcBuffer_Allocate(8);
+ * parcBuffer_PutUint64(payload, 5432L);
+ *
+ * ccnxInterest_SetPayload(interest, payload);
+ *
+ * parcBuffer_Release(&payload);
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&instance);
+ * }
+ * @endcode
+ * @see `CCNxPayloadType`
+ */
+bool ccnxInterest_SetPayloadAndId(CCNxInterest *interest, const PARCBuffer *payload);
+
+
+/**
+ * Set the payload and specified payloadId on an `CCnxInterest` instance. A reference to the
+ * supplied payload is acquired by the Interest, so the caller may release the payload after
+ * setting it on the CCnxInterest. The payload type must be specified, and must be one of the types
+ * defined in {@link CCNxPayloadType}.
+ *
+ * This will append the supplied payloadId to the interest name, supplying a NULL payloadId will result
+ * in not payloadId being appended to the interest name. See {@link CCNxInterestPayloadId}
+ *
+ * @param [in] interest A pointer to the `CCNxInstance` instance to update.
+ * @param [in] payload A pointer to the PARCBuffer payload to be applied to the `CCNxInterest`.
+ * @param [in] payloadId A pointer to a CCNxInterestPayloadId to use instead of the default. The value may
+ * be NULL of no payload id is desired.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/11");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * PARCBuffer *payload = parcBuffer_Allocate(8);
+ * parcBuffer_PutUint64(payload, 5432L);
+ *
+ * CCNxInterestPayloadId *payloadId = ccnxInterestPayloadId_CreateAsSHA256Hash(payload);
+ * ccnxInterest_SetPayloadWithId(interest, payload, payloadId);
+ * ccnxInterestPayloadId_Release(&payloadId);
+ *
+ * parcBuffer_Release(&payload);
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&instance);
+ * }
+ * @endcode
+ * @see `CCNxPayloadType`
+ */
+bool ccnxInterest_SetPayloadWithId(CCNxInterest *interest, const PARCBuffer *payload, const CCNxInterestPayloadId *payloadId);
+
+
+/**
+ * Return a pointer to the payload attached to the specified `CCNxInterest`, if any. It is up to the
+ * caller to acquire a reference to the payload if necessary.
+ *
+ * @param [in] interest A pointer to the `CCNxInstance` instance to update.
+ * @return A pointer to the payload buffer attached to the supplied `CCNxInterest` instance. Will be NULL
+ * if the `CCNxInterest` instance has no payload.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/11");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * PARCBuffer *payload = parcBuffer_Allocate(8);
+ * parcBuffer_PutUint64(payload, 5432L);
+ *
+ * ccnxInterest_SetPayload(interest, CCNxPayloadType_DATA, payload);
+ *
+ * PARCBuffer *reference = ccnxInterest_GetPayload(interest);
+ *
+ * parcBuffer_Release(&payload);
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&instance);
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxInterest_GetPayload(const CCNxInterest *interest);
+
+/**
+ * Set the Hop Limit for the specified `CCNxInterest` instance.
+ * The Interest HopLimit element is a counter that is decremented with each hop. It limits the distance an Interest may travel.
+ * The node originating the Interest may put in any value - up to the maximum - in network byte order. Each node that receives
+ * an Interest with a HopLimit decrements the value upon reception. If the value is 0 after the decrement, the Interest cannot
+ * be forwarded off the node.
+ *
+ * @param [in] interest A pointer to a `CCNxInterest` instance to update.
+ * @param [in] hopLimit The hop limit to set.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/11");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * ccnxInterest_SetHopLimit(interest, 30);
+ *
+ * uint32_t hopLimit = ccnxInterest_GetHopLimit(interest);
+ * assertTrue(hopLimit = 30, "Expected 30 for the hopLimit");
+ *
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&instance);
+ * }
+ * @endcode
+ * @see `ccnxInterest_GetHopLimit`
+ */
+bool ccnxInterest_SetHopLimit(CCNxInterest *interest, uint32_t hopLimit);
+
+/**
+ * Get the Hop Limit for the specified `CCNxInterest` instance.
+ * The Interest HopLimit element is a counter that is decremented with each hop. It limits the distance an Interest may travel.
+ * The node originating the Interest may put in any value - up to the maximum - in network byte order. Each node that receives
+ * an Interest with a HopLimit decrements the value upon reception. If the value is 0 after the decrement, the Interest cannot
+ * be forwarded off the node.
+ *
+ * @param [in] interest A pointer to the `CCNxInterest` from which to retrieve the Hop Limit
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/11");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * ccnxInterest_SetHopLimit(interest, 30);
+ *
+ * uint32_t hopLimit = ccnxInterest_GetHopLimit(interest);
+ * assertTrue(hopLimit = 30, "Expected 30 for the hopLimit");
+ *
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&instance);
+ * }
+ * @endcode
+ * @see `ccnxInterest_SetHopLimit`
+ */
+uint32_t ccnxInterest_GetHopLimit(const CCNxInterest *interest);
+#endif // libccnx_ccnx_Interest_h
diff --git a/libccnx-common/ccnx/common/ccnx_InterestPayloadId.c b/libccnx-common/ccnx/common/ccnx_InterestPayloadId.c
new file mode 100755
index 00000000..84e653f7
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_InterestPayloadId.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/ccnx_InterestPayloadId.h>
+#include <ccnx/common/ccnx_NameSegment.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Object.h>
+
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_CryptoHash.h>
+#include <parc/security/parc_CryptoHasher.h>
+
+struct ccnx_interest_payload_id {
+ CCNxNameSegment *nameSegment;
+ uint8_t type;
+};
+
+static void
+_destroy(CCNxInterestPayloadId **idP)
+{
+ CCNxInterestPayloadId *id = *idP;
+ ccnxNameSegment_Release(&id->nameSegment);
+}
+
+parcObject_ExtendPARCObject(CCNxInterestPayloadId, _destroy, ccnxInterestPayloadId_Copy, ccnxInterestPayloadId_ToString,
+ ccnxInterestPayloadId_Equals, ccnxInterestPayloadId_Compare, NULL, NULL);
+
+parcObject_ImplementAcquire(ccnxInterestPayloadId, CCNxInterestPayloadId);
+
+parcObject_ImplementRelease(ccnxInterestPayloadId, CCNxInterestPayloadId);
+
+CCNxInterestPayloadId *
+ccnxInterestPayloadId_Create(const PARCBuffer *data, uint8_t type)
+{
+ CCNxInterestPayloadId *result = parcObject_CreateInstance(CCNxInterestPayloadId);
+ parcBuffer_AssertValid(data);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(parcBuffer_Capacity(data) + 1);
+ assertTrue(type > CCNxInterestPayloadId_TypeCode_App, "App type must be greater than 0x80");
+
+ parcBuffer_PutUint8(buffer, type);
+ parcBuffer_PutBuffer(buffer, data);
+ parcBuffer_Flip(buffer);
+ result->nameSegment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_PAYLOADID, buffer);
+ parcBuffer_Release(&buffer);
+
+ return result;
+}
+
+CCNxInterestPayloadId *
+ccnxInterestPayloadId_CreateAsSHA256Hash(const PARCBuffer *data)
+{
+ CCNxInterestPayloadId *result = parcObject_CreateInstance(CCNxInterestPayloadId);
+
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBuffer(hasher, data);
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ parcCryptoHasher_Release(&hasher);
+
+ PARCBuffer *hashData = parcCryptoHash_GetDigest(hash);
+ PARCBuffer *codedHash = parcBuffer_Allocate(parcBuffer_Capacity(hashData) + 1);
+ parcBuffer_PutUint8(codedHash, CCNxInterestPayloadId_TypeCode_RFC6920_SHA256);
+ parcBuffer_PutBuffer(codedHash, hashData);
+ parcBuffer_Flip(codedHash);
+
+ result->nameSegment =
+ ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_PAYLOADID, codedHash);
+
+ parcBuffer_Release(&codedHash);
+ parcCryptoHash_Release(&hash);
+
+ return result;
+}
+
+static CCNxInterestPayloadId *
+_ccnxInterestPayloadId_CreateFromNameSegment(const CCNxNameSegment *nameSegment)
+{
+ ccnxNameSegment_AssertValid(nameSegment);
+ assertTrue(ccnxNameSegment_GetType(nameSegment) == CCNxNameLabelType_PAYLOADID,
+ "ccnxInterestPayloadId_CreateFromNameSegment: supplied nameSegment is not a PayloadId");
+ if (ccnxNameSegment_GetType(nameSegment) != CCNxNameLabelType_PAYLOADID) {
+ return NULL;
+ }
+ CCNxInterestPayloadId *result = parcObject_CreateInstance(CCNxInterestPayloadId);
+ result->nameSegment = ccnxNameSegment_Acquire(nameSegment);
+
+ return result;
+}
+
+CCNxInterestPayloadId *
+ccnxInterestPayloadId_CreateFromSegmentInName(const CCNxName *name)
+{
+ ccnxName_AssertValid(name);
+
+ CCNxInterestPayloadId *result = NULL;
+ size_t count = ccnxName_GetSegmentCount(name);
+ for (size_t i = 0; i < count; ++i) {
+ CCNxNameSegment *segment = ccnxName_GetSegment(name, i);
+ if (ccnxNameSegment_GetType(segment) == CCNxNameLabelType_PAYLOADID) {
+ result = _ccnxInterestPayloadId_CreateFromNameSegment(segment);
+ break;
+ }
+ }
+
+ return result;
+}
+
+
+
+const CCNxNameSegment *
+ccnxInterestPayloadId_GetNameSegment(const CCNxInterestPayloadId *id)
+{
+ return id->nameSegment;
+}
+
+PARCBuffer *
+ccnxInterestPayloadId_GetValue(const CCNxInterestPayloadId *id)
+{
+ PARCBuffer *data = ccnxNameSegment_GetValue(id->nameSegment);
+ parcBuffer_Rewind(data);
+ parcBuffer_SetPosition(data, 1);
+ return data;
+}
+
+uint8_t
+ccnxInterestPayloadId_GetType(const CCNxInterestPayloadId *id)
+{
+ PARCBuffer *data = ccnxNameSegment_GetValue(id->nameSegment);
+ parcBuffer_Rewind(data);
+ uint8_t type = parcBuffer_GetUint8(data);
+ return type;
+}
+
+
+void
+ccnxInterestPayloadId_AssertValid(const CCNxInterestPayloadId *id)
+{
+ trapIllegalValueIf(ccnxInterestPayloadId_IsValid(id) == false, "CCNxName instance is not valid.");
+}
+
+bool
+ccnxInterestPayloadId_IsValid(const CCNxInterestPayloadId *id)
+{
+ bool result = false;
+ if (ccnxNameSegment_IsValid(id->nameSegment)) {
+ result = true;
+ }
+ return result;
+}
+
+char *
+ccnxInterestPayloadId_ToString(const CCNxInterestPayloadId *id)
+{
+ ccnxInterestPayloadId_AssertValid(id);
+
+ return ccnxNameSegment_ToString(id->nameSegment);
+}
+
+CCNxInterestPayloadId *
+ccnxInterestPayloadId_Copy(const CCNxInterestPayloadId *sourceId)
+{
+ ccnxInterestPayloadId_AssertValid(sourceId);
+
+ CCNxInterestPayloadId *result =
+ _ccnxInterestPayloadId_CreateFromNameSegment(sourceId->nameSegment);
+ return result;
+}
+
+bool
+ccnxInterestPayloadId_Equals(const CCNxInterestPayloadId *id1, const CCNxInterestPayloadId *id2)
+{
+ ccnxInterestPayloadId_AssertValid(id1);
+ ccnxInterestPayloadId_AssertValid(id2);
+
+ bool result = ((id1 == id2) ||
+ (ccnxNameSegment_Equals(id1->nameSegment, id2->nameSegment)));
+ return result;
+}
+
+uint32_t
+ccnxInterestPayloadId_HashCode(const CCNxInterestPayloadId *id)
+{
+ ccnxInterestPayloadId_AssertValid(id);
+ return ccnxNameSegment_HashCode(id->nameSegment);
+}
+
+
+int
+ccnxInterestPayloadId_Compare(const CCNxInterestPayloadId *id1, const CCNxInterestPayloadId *id2)
+{
+ ccnxInterestPayloadId_AssertValid(id1);
+ ccnxInterestPayloadId_AssertValid(id2);
+
+ int result = ccnxNameSegment_Compare(id1->nameSegment, id2->nameSegment);
+ return result;
+}
diff --git a/libccnx-common/ccnx/common/ccnx_InterestPayloadId.h b/libccnx-common/ccnx/common/ccnx_InterestPayloadId.h
new file mode 100755
index 00000000..cd3d6fce
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_InterestPayloadId.h
@@ -0,0 +1,518 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_InterestPayloadId.h
+ * @ingroup Naming
+ * @brief The basic CCNx InterestPayloadId.
+ *
+ *
+ */
+#ifndef libccnx_ccnx_InterestPayloadId_h
+#define libccnx_ccnx_InterestPayloadId_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <ccnx/common/ccnx_NameSegment.h>
+#include <ccnx/common/ccnx_Name.h>
+//#include <parc/security/parc_CryptoHashType.h>
+
+struct ccnx_interest_payload_id;
+/**
+ * @typedef CCNxInterestPayloadId
+ * @brief An RFC3986 URI compliant identifier in which each path segment carries a label.
+ */
+typedef struct ccnx_interest_payload_id CCNxInterestPayloadId;
+
+
+typedef enum {
+ //RFC 6920
+ CCNxInterestPayloadId_TypeCode_RFC6920_Reserved = 0x00,
+ CCNxInterestPayloadId_TypeCode_RFC6920_SHA256 = 0x01, //256 bits
+ CCNxInterestPayloadId_TypeCode_RFC6920_SHA256_128 = 0X02, //128 bits
+ CCNxInterestPayloadId_TypeCode_RFC6920_SHA256_120 = 0X03, //120 bits
+ CCNxInterestPayloadId_TypeCode_RFC6920_SHA256_96 = 0X04, //96 bits
+ CCNxInterestPayloadId_TypeCode_RFC6920_SHA256_64 = 0X05, //64 bits
+ CCNxInterestPayloadId_TypeCode_RFC6920_SHA256_32 = 0x06, //32 bits
+ //PARC
+ CCNxInterestPayloadId_TypeCode_App = 0x80,
+ CCNxInterestPayloadId_TypeCode_Nonce = 0x81
+} CCNxInterestPayloadId_TypeCode;
+
+
+/**
+ * Create a new instance of a `CCNxInterestPayloadId` that uses the provided
+ * PARCBuffer as the ID. The instance is dynamically allocated and must be released by
+ * calling {@link ccnxInterestPayloadId_Release}.
+ *
+ * @param [in] data a PARCBuffer to be used as the body of the KeyId name segment.
+ * @param [in] type a uint8_t, nominally one of the CCNxInterestPayloadId_TypeCodes,
+ * which is prepended to the data.
+ *
+ * @return A pointer to a `CCNxInterestPayloadId` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *somePaylaod = ....
+ * CCNxInterest *someInterest = ....
+ *
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Key_42");
+ * CCNxInterestPayloadId *interestPayloadId =
+ * ccnxInterestPayloadId_Create(data, InterestPayloadIdType_App);
+ * parcBuffer_Release(&buffer);
+ *
+ * ccnxInterest_SetPayloadAndId(someInterest, somePayload, interestPayloadId);
+ * ccnxInterestPayloadId_Release(&interestPayloadId);
+ * parcBuffer_Release(&somePayload);
+ *
+ * ...
+ *
+ * }
+ * @endcode
+ */
+CCNxInterestPayloadId *
+ccnxInterestPayloadId_Create(const PARCBuffer *data, uint8_t type);
+
+
+/**
+ * Create a new instance of a `CCNxInterestPayloadId` that is a sha256 hash of the
+ * input data. The instance is dynamically allocated and must be released by
+ * calling {@link ccnxInterestPayloadId_Release}.
+ *
+ * @param [in] data a PARCBuffer to be hashed to obtain the ID bytes.
+ *
+ * @return A pointer to a `CCNxInterestPayloadId` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *somePaylaod = ....
+ * CCNxInterest *someInterest = ....
+ *
+ * CCNxInterestPayloadId *interestPayloadId =
+ * ccnxInterestPayloadId_CreateAsSHA256Hash(somePayload);
+ *
+ * ccnxInterest_SetPayloadAndId(someInterest, somePayload, interestPayloadId);
+ * ccnxInterestPayloadId_Release(&interestPayloadId);
+ * parcBuffer_Release(&somePayload);
+ *
+ * ...
+ *
+ * }
+ * @endcode
+ */
+CCNxInterestPayloadId *
+ccnxInterestPayloadId_CreateAsSHA256Hash(const PARCBuffer *data);
+
+/**
+ * Create a new instance of a `CCNxInterestPayloadId` from an Interest Payload Id name
+ * segment if one is present in the provided {@link CCNxName}, otherwise return
+ * NULL. The instance is dynamically allocated and must be released by calling {@link
+ * ccnxInterestPayloadId_Release}.
+ *
+ * @param [in] name a CCNxName that may or may not carry an Interest Payload Id CCNxNameSegment.
+ *
+ * @return A pointer to a `CCNxInterestPayloadId` instance or NULL if no
+ * Interest-Payload-Id typed CCNxNameSegment is found.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *someName = ...
+ *
+ * CCNxInterestPayloadId *interestPayloadId =
+ * ccnxInterestPayloadId_CreateFromSegmentInName(someName);
+ *
+ * if (interestPayloadId != NULL) {
+ * ....
+ * ccnxInterestPayloadId_Release(&interestPayloadId);
+ * }
+ *
+ * ...
+ *
+ * ccnxName_Release(&someName);
+ * }
+ * @endcode
+ */
+CCNxInterestPayloadId *
+ccnxInterestPayloadId_CreateFromSegmentInName(const CCNxName *name);
+
+/**
+ * Get a pointer to a CCNxNameSegment derived from the provided
+ * CCNxInterestPayloadId. There is no need to release the returned CCNxNameSegment
+ * object.
+ *
+ * @param [in] interestPayloadId A pointer to the `CCNxInterestPayloadId` instance.
+ *
+ * @return A pointer to a CCNxNameSegment.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *someName = ...
+ *
+ * CCNxInterestPayloadId *interestPayloadId =
+ * ccnxInterestPayloadId_CreateFromSegmentInName(someName);
+ *
+ * if (interestPayloadId != NULL) {
+ * CCNxNameSegmemt *nameSegment = ccnxInterestPayloadId_GetNameSegment(interestPayloadId);
+ * ....
+ * ccnxInterestPayloadId_Release(&interestPayloadId);
+ * }
+ *
+ * ...
+ *
+ * ccnxName_Release(&someName);
+ * }
+ * @endcode
+ */
+const CCNxNameSegment *
+ccnxInterestPayloadId_GetNameSegment(const CCNxInterestPayloadId *interestPayloadId);
+
+/**
+ * Get the CCNxInterestPayloadId's value as a PARCBuffer. There is no need to release
+ * the returned PARCBuffer object.
+ *
+ * @param [in] interestPayloadId A pointer to the `CCNxInterestPayloadId` instance.
+ *
+ * @return A pointer to a PARCBuffer object containing the Id bytes.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *someName = ...
+ *
+ * CCNxInterestPayloadId *interestPayloadId =
+ * ccnxInterestPayloadId_CreateFromSegmentInName(someName);
+ *
+ * if (interestPayloadId != NULL) {
+ * PARCBuffer *ipIdValue = ccnxInterestPayloadId_GetValue(interestPayloadId);
+ * ....
+ * ccnxInterestPayloadId_Release(&interestPayloadId);
+ * }
+ *
+ * ...
+ *
+ * ccnxName_Release(&someName);
+ * }
+ * @endcode
+ */
+PARCBuffer *
+ccnxInterestPayloadId_GetValue(const CCNxInterestPayloadId *interestPayloadId);
+
+/**
+ * Get the CCNxInterestPayloadId's uint8 type.
+ *
+ * @param [in] interestPayloadId A pointer to the `CCNxInterestPayloadId` instance.
+ *
+ * @return A uint8_t containing the type value.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *someName = ...
+ *
+ * CCNxInterestPayloadId *interestPayloadId =
+ * ccnxInterestPayloadId_CreateFromSegmentInName(someName);
+ *
+ * if (interestPayloadId != NULL) {
+ * uint8_t type = ccnxInterestPayloadId_GetType(interestPayloadId);
+ * ....
+ * ccnxInterestPayloadId_Release(&interestPayloadId);
+ * }
+ *
+ * ...
+ *
+ * ccnxName_Release(&someName);
+ * }
+ * @endcode
+ */
+uint8_t
+ccnxInterestPayloadId_GetType(const CCNxInterestPayloadId *interestPayloadId);
+
+/**
+ * Increase the number of references to a `CCNxInterestPayloadId` instance.
+ *
+ * Note that a new `CCNxInterestPayloadId` is not created, only that the given
+ * `CCNxInterestPayloadId` reference count is incremented. Discard the reference by
+ * invoking {@link ccnxInterestPayloadId_Release}.
+ *
+ * @param [in] interestPayloadId A pointer to the original `CCNxInterestPayloadId`.
+ *
+ * @return The value of the input parameter @p interestPayloadId.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterestPayloadId *original = ccnxInterestPayloadId_CreateAsSHA256Hash(...);
+ *
+ * CCNxInterestPayloadId *reference = ccnxInterestPayloadId_Acquire(original);
+ *
+ * ccnxInterestPayloadId_Release(&original);
+ * ccnxInterestPayloadId_Release(&reference); //Triggers final cleanup
+ * }
+ * @endcode
+ *
+ * @see ccnxInterestPayloadId_Release
+ */
+CCNxInterestPayloadId *
+ccnxInterestPayloadId_Acquire(const CCNxInterestPayloadId *interestPayloadId);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in] interestPayloadIdP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterestPayloadId *interestPayloadId = ccnxInterestPayloadId_CreateAsSHA256Hash(...);
+ *
+ * ccnxInterestPayloadId_Release(&interestPayloadId);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterestPayloadId_Acquire}
+ */
+void
+ccnxInterestPayloadId_Release(CCNxInterestPayloadId **interestPayloadIdP);
+
+/**
+ * Assert that an instance of `CCNxInterestPayloadId` is valid. If the instance is not
+ * valid, terminate via {@link trapIllegalValue}. Valid means the internal state of the
+ * type is consistent with its required current or future behavior. This may include the
+ * validation of internal instances of types.
+ *
+ * @param [in] interestPayloadId A pointer to a `CCNxInterestPayloadId` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterestPayloadId *interestPayloadId = ccnxInterestPayloadId_CreateAsSHA256Hash(...);
+ *
+ * ccnxInterestPayloadId_AssertValid(interestPayloadId);
+ *
+ * ccnxInterestPayloadId_Release(&interestPayloadId);
+ * }
+ * @endcode
+ */
+void
+ccnxInterestPayloadId_AssertValid(const CCNxInterestPayloadId *interestPayloadId);
+
+/**
+ * Determine if an instance of `CCNxInterestPayloadId` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current
+ * or future behavior. This may include the validation of internal instances of
+ * types.
+ *
+ * @param [in] interestPayloadId A pointer to a `CCNxInterestPayloadId` instance.
+ *
+ * @return true If the instance is valid.
+ * @return false if the instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterestPayloadId *interestPayloadId = ccnxInterestPayloadId_CreateAsSHA256Hash(...);
+ *
+ * if (ccnxInterestPayloadId_IsValid(interestPayloadId) == true) {
+ * ...
+ * }
+ *
+ * ccnxInterestPayloadId_Release(&interestPayloadId);
+ * }
+ * @endcode
+ */
+bool
+ccnxInterestPayloadId_IsValid(const CCNxInterestPayloadId *interestPayloadId);
+
+/**
+ * Produce a null-terminated string representation of the specified instance. The
+ * non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] interestPayloadId A pointer to the `CCNxInterestPayloadId` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be
+ * deallocated via `parcMemory_Deallocate()`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterestPayloadId *instance = ccnxInterestPayloadId_CreateAsSHA256Hash(...);
+ *
+ * char *string = ccnxInterestPayloadId_ToString(instance);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate(string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * ccnxInterestPayloadId_Release(&instance);
+ * }
+ * @endcode
+ */
+char *
+ccnxInterestPayloadId_ToString(const CCNxInterestPayloadId *interestPayloadId);
+
+/**
+ * Create a copy of the specified `CCNxInterestPayloadId` instance, producing a new,
+ * independent, instance from dynamically allocated memory. This a deep copy, all
+ * referenced memory is copied. The created instance of `CCNxInterestPayloadId` must be
+ * released by calling {@link ccnxInterestPayloadId_Release}().
+ *
+ * @param [in] interestPayloadId The `CCNxInterestPayloadId` to copy
+ *
+ * @return A new, independent copy of the given `CCNxInterestPayloadId`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterestPayloadId *interestPayloadId = ccnxInterestPayloadId_CreateAsSHA256Hash(...);
+ * CCNxInterestPayloadId *copy = ccnxInterestPayloadId_Copy(interestPayloadId);
+ *
+ * ...
+ *
+ * ccnxInterestPayloadId_Release(&interestPayloadId);
+ * ccnxInterestPayloadId_Release(&copy);
+ * }
+ * @endcode
+ */
+CCNxInterestPayloadId *
+ccnxInterestPayloadId_Copy(const CCNxInterestPayloadId *interestPayloadId);
+
+/**
+ * Determine if two `CCNxInterestPayloadId` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxInterestPayloadId` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `ccnxInterestPayloadId_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxInterestPayloadId_Equals(x, y)` must return true if and only if
+ * `ccnxInterestPayloadId_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxInterestPayloadId_Equals(x, y)` returns true and
+ * `ccnxInterestPayloadId_Equals(y, z)` returns true,
+ * then `ccnxInterestPayloadId_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxInterestPayloadId_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxInterestPayloadId_Equals(x, NULL)` must return false.
+ *
+ * @param [in] interestPayloadId1 A pointer to a `CCNxInterestPayloadId` instance.
+ * @param [in] interestPayloadId2 A pointer to a `CCNxInterestPayloadId` instance.
+ *
+ * @return True If the given `CCNxInterestPayloadId` instances are equal
+ * @return False Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterestPayloadId *a = ccnxInterestPayloadId_CreateAsSHA256Hash(...);
+ * CCNxInterestPayloadId *b = ccnxInterestPayloadId_CreateAsSHA256Hash(...);
+ *
+ * if (ccnxInterestPayloadId_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * ccnxInterestPayloadId_Release(&a);
+ * ccnxInterestPayloadId_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterestPayloadId_Compare}
+ */
+bool
+ccnxInterestPayloadId_Equals(const CCNxInterestPayloadId *interestPayloadId1, const CCNxInterestPayloadId *interestPayloadId2);
+
+/**
+ * Compare @p interestPayloadId1 to @p interestPayloadId2 using CCNx canonical ordering (shortlex).
+ *
+ * `NULL` is considered the shortest interestPayloadId, so `(NULL, non-NULL) -> -1` and
+ * `(NULL, NULL) -> 0`, `(non-NULL, NULL) -> +1`.
+ *
+ * @param [in] interestPayloadId1 A pointer to a `CCNxInterestPayloadId` instance.
+ * @param [in] interestPayloadId2 A pointer to a `CCNxInterestPayloadId` instance.
+ *
+ * Returns:
+ * <ul>
+ * <li>-1 for interestPayloadId1 < interestPayloadId2</li>
+ * <li> 0 for interestPayloadId1 = interestPayloadId2</li>
+ * <li>+1 for interestPayloadId1 > interestPayloadId2</li>
+ * </ul>
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterestPayloadId *a = ccnxInterestPayloadId_CreateAsSHA256Hash(...);
+ * CCNxInterestPayloadId *b = ccnxInterestPayloadId_CreateAsSHA256Hash(...);
+ *
+ * if (ccnxInterestPayloadId_Compare(a, b) == 0) {
+ * ...
+ * }
+ *
+ * ccnxInterestPayloadId_Release(&a);
+ * ccnxInterestPayloadId_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterestPayloadId_Equals}
+ */
+int
+ccnxInterestPayloadId_Compare(const CCNxInterestPayloadId *interestPayloadId1, const CCNxInterestPayloadId *interestPayloadId2);
+
+/**
+ * Retrieve the hashcode of the CCNxInterestPayloadId.
+ *
+ * @param [in] id A pointer to a `CCNxINterestPayloadId` instance.
+ *
+ * @return uint32_t The hashcode
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *someName = ...
+ *
+ * CCNxInterestPayloadId *interestPayloadId =
+ * ccnxInterestPayloadId_CreateFromSegmentInName(someName);
+ *
+ * if (interestPayloadId != NULL) {
+ * uint32_t hashcode = ccnxInterestPayloadId_HashCode(interestPayloadId);
+ * ....
+ * ccnxInterestPayloadId_Release(&interestPayloadId);
+ * }
+ *
+ * ...
+ *
+ * ccnxName_Release(&someName);
+ * }
+ * @endcode
+ */
+uint32_t
+ccnxInterestPayloadId_HashCode(const CCNxInterestPayloadId *id);
+#endif // libccnx_ccnx_InterestPayloadId_h
diff --git a/libccnx-common/ccnx/common/ccnx_InterestReturn.c b/libccnx-common/ccnx/common/ccnx_InterestReturn.c
new file mode 100755
index 00000000..26527f58
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_InterestReturn.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/ccnx_InterestReturn.h>
+#include <ccnx/common/ccnx_Interest.h>
+#include <ccnx/common/internal/ccnx_InterestReturnFacadeV1.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_Object.h>
+
+static const CCNxInterestReturnInterface *_defaultImpl = &CCNxInterestReturnFacadeV1_Implementation;
+
+CCNxInterestReturn *
+ccnxInterestReturn_CreateWithImpl(const CCNxInterestReturnInterface *impl,
+ const CCNxInterest *interest,
+ CCNxInterestReturn_ReturnCode returnCode)
+{
+ //The impl must do an Acquire
+
+ CCNxInterestReturn *result = impl->Create(interest, returnCode);
+
+ // And set the dictionary's interface pointer to the one we just used to create this.
+ ccnxTlvDictionary_SetMessageInterface(result, impl);
+
+ return result;
+}
+
+
+// Canonical Functions
+CCNxInterestReturn *
+ccnxInterestReturn_Create(const CCNxInterest *interest, CCNxInterestReturn_ReturnCode returnCode)
+{
+ CCNxInterestReturn *result =
+ ccnxInterestReturn_CreateWithImpl(_defaultImpl, interest, returnCode);
+ return result;
+}
+
+void
+ccnxInterestReturn_AssertValid(const CCNxInterestReturn *interestReturn)
+{
+ assertNotNull(interestReturn, "Must be a non-null pointer to a CCNxInterestReturn.");
+ // Check for required fields in the underlying dictionary. Case 1036
+ CCNxInterestReturnInterface *impl = ccnxInterestReturnInterface_GetInterface(interestReturn);
+ assertNotNull(impl, "Interest must have an valid implementation pointer.");
+
+ if (impl->AssertValid) {
+ impl->AssertValid(interestReturn);
+ } else {
+ trapNotImplemented("ccnxInterest_GetName");
+ }
+}
+
+CCNxInterestReturn *
+ccnxInterestReturn_Acquire(const CCNxInterestReturn *instance)
+{
+ return ccnxTlvDictionary_Acquire(instance);
+}
+
+void
+ccnxInterestReturn_Release(CCNxInterestReturn **instance)
+{
+ ccnxTlvDictionary_Release(instance);
+}
+
+bool
+ccnxInterestReturn_Equals(const CCNxInterestReturn *a, const CCNxInterestReturn *b)
+{
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (a == b) {
+ return true;
+ }
+
+ CCNxInterestReturnInterface *impl = ccnxInterestReturnInterface_GetInterface(a);
+ CCNxInterestReturnInterface *implB = ccnxInterestReturnInterface_GetInterface(b);
+
+ if (impl != implB) {
+ return false;
+ }
+
+ if (impl->GetReturnCode(a) != impl->GetReturnCode(b)) {
+ return false;
+ }
+
+ return ccnxInterest_Equals(a, b);
+}
+
+char *
+ccnxInterestReturn_ToString(const CCNxInterestReturn *interestReturn)
+{
+ ccnxInterestReturn_AssertValid(interestReturn);
+
+ char *name = ccnxName_ToString(ccnxInterest_GetName(interestReturn));
+
+ CCNxInterestReturnInterface *impl = ccnxInterestReturnInterface_GetInterface(interestReturn);
+ CCNxInterestReturn_ReturnCode code = impl->GetReturnCode(interestReturn);
+
+ char *string;
+ int len = asprintf(&string, "CCNxInterestReturn{.code=%dms .name=\"%s\"}", code, name);
+ if (len < 0) {
+ //We have serious problems.
+ return name;
+ }
+
+ parcMemory_Deallocate((void **) &name);
+
+ char *result = parcMemory_StringDuplicate(string, strlen(string));
+ free(string);
+
+ return result;
+}
+
+// Accessors Functions
+CCNxInterestReturn_ReturnCode
+ccnxInterestReturn_GetReturnCode(const CCNxInterestReturn *interestReturn)
+{
+ ccnxInterestReturn_AssertValid(interestReturn);
+ CCNxInterestReturnInterface *impl = ccnxInterestReturnInterface_GetInterface(interestReturn);
+ CCNxInterestReturn_ReturnCode code = impl->GetReturnCode(interestReturn);
+ return code;
+}
+
diff --git a/libccnx-common/ccnx/common/ccnx_InterestReturn.h b/libccnx-common/ccnx/common/ccnx_InterestReturn.h
new file mode 100755
index 00000000..44bb48aa
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_InterestReturn.h
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_InterestReturn.h
+ * @ingroup InterestRetrun
+ * @brief A CCNx InterestReturn is an optional error response for an Interest that can't be satisfied by the returning entity
+ *
+ * An InterestReturn is a convience type for a returned Interest. It is created from an CCNxInterest and a return code
+ * with the intent of returning the interest to the previous hop. Other than modifing the PacketType to indicate that it
+ * is a Interest Return, it wraps and preserves the state of the provided CCNxInterest and can be used with CCNxInterest
+ * functions as if it were a CCNxInterest type.
+ *
+ * The possible return codes are:
+ *
+ * +--------------------+
+ * | No Route |
+ * | |
+ * | Hop Limit Exceeded |
+ * | |
+ * | No Resources |
+ * | |
+ * | Path Error |
+ * | |
+ * | Prohibited |
+ * | |
+ * | Congested |
+ * | |
+ * | MTU too large |
+ * +--------------------+
+ *
+ * @see {@link CCNxInterest}
+ *
+ */
+
+#ifndef libccnx_ccnx_InterestReturn_h
+#define libccnx_ccnx_InterestReturn_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/ccnx_Interest.h>
+
+/**
+ * @typedef CCNxInterestReturn
+ * @brief The CCNx InterestReturn Message
+ */
+typedef CCNxTlvDictionary CCNxInterestReturn;
+
+/**
+ * @typedef CCNxInterestReturn_ReturnCode
+ * @brief The CCNx InterestReturn ReturnCode options
+ */
+typedef enum {
+ CCNxInterestReturn_ReturnCode_NoRoute = 1,
+ CCNxInterestReturn_ReturnCode_HopLimitExceeded = 2,
+ CCNxInterestReturn_ReturnCode_NoResources = 3,
+ CCNxInterestReturn_ReturnCode_PathError = 4,
+ CCNxInterestReturn_ReturnCode_Prohibited = 5,
+ CCNxInterestReturn_ReturnCode_Congestion = 6,
+ CCNxInterestReturn_ReturnCode_MTUTooLarge = 7,
+ CCNxInterestReturn_ReturnCode_END = 8
+} CCNxInterestReturn_ReturnCode;
+
+/**
+ * Create a new instance of `CCNxInterestRetrun` from the specified CCNxInterest, with the specified return code.
+ *
+ * The created instance of `CCNxInterestReturn` must be released by calling {@link ccnxInterestReturn_Release}().
+ *
+ * @param [in] interest A pointer to the {@link CCNxInterest} to be returned.
+ * @param [in] returnCode The {@link CCNxInterestReturn_ReturnCode} to return.
+ *
+ * @return A new instance of a `CCNxInterestReturn`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterest *interest = ...
+ *
+ * CCNxInterestReturn *interestToReturn = ccnxInterest_Create(interest, CCNxInterestReturn_ReturnCode_NoRoute);
+ *
+ * ...
+ *
+ * ccnxInterestReturn_Release(&interestToReturn);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterestReturn_Release}
+ */
+CCNxInterestReturn *
+ccnxInterestReturn_Create(const CCNxInterest *interest, CCNxInterestReturn_ReturnCode returnCode);
+
+
+/**
+ * Retrieve the specified `CCNxInterestReturn`'s {@link CCNxInterestReturn_ReturnCode}
+ *
+ * @return The return code for the specified CCNxInterestReturn.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(...);
+ * CCNxInterestReturn *interestReturn = ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_NoRoute);
+ *
+ * ...
+ *
+ * CCNxInterestReturn_ReturnCode returnCode = ccnxInterest_GetReturnCode(interestReturn);
+ *
+ * ...
+ *
+ * ccnxInterestReturn_Release(&interestReturn);
+ * }
+ * @endcode
+ *
+ */
+CCNxInterestReturn_ReturnCode
+ccnxInterestReturn_GetReturnCode(const CCNxInterestReturn *interestReturn);
+
+
+// Canonocal
+/**
+ * Increase the number of references to a `CCNxInterestReturn`.
+ *
+ * Note that a new `CCNxInterestReturn` is not created,
+ * only that the given `CCNxInterestReturn` reference count is incremented.
+ * Discard the reference by invoking {@link ccnxInterestReturn_Release}.
+ *
+ * @param [in] instance A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterestReturn *reference = ccnxInterestReturn_Acquire(interestReturn);
+ *
+ * ...
+ *
+ * ccnxInterestReturn_Release(&reference);
+ *
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterestReturn_Release}
+ */
+
+CCNxInterestReturn *
+ccnxInterestReturn_Acquire(const CCNxInterestReturn *instance);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instanceP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterestReturn *reference = ccnxInterestReturn_Acquire(contentObject);
+ *
+ * ...
+ *
+ * ccnxInterestReturn_Release(&reference);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxInterestReturn_Acquire}
+ */
+void
+ccnxInterestReturn_Release(CCNxInterestReturn **instanceP);
+
+/**
+ * Determine if two `CCNxInterestReturn` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxInterestReturn` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `ccnxInterestReturn_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `ccnxInterestReturn_Equals(x, y)` must return true if and only if
+ * `ccnxInterestReturn_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxInterestReturn_Equals(x, y)` returns true and
+ * `ccnxInterestReturn_Equals(y, z)` returns true,
+ * then `ccnxInterestReturn_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `ccnxInterestReturn_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxInterestReturn_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param interestReturnA A pointer to a `CCNxInterestReturn` instance.
+ * @param interestReturnB A pointer to a `CCNxInterestReturn` instance.
+ * @return true if the two `CCNxInterestReturn` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * CCNxInterestReturn *interestReturnA = ccnxInterestReturn_Create(interestA, CCNxInterestReturn_ReturnCode_NoRoute);
+ * CCNxInterestReturn *interestReturnB = ccnxInterestReturn_Create(interestA, CCNxInterestReturn_ReturnCode_NoRoute); // same as A
+ * CCNxInterestReturn *interestReturnC = ccnxInterestReturn_Create(interestA, CCNxInterestReturn_ReturnCode_HopLimitExceeded ); // different
+ *
+ * if (ccnxInterestReturn_Equals(interestReturnA, interestReturnB)) {
+ * // this is expected...
+ * }
+ *
+ * if (ccnxInterestReturn_Equals(interestReturnA, interestReturnC)) {
+ * // this is NOT expected
+ * }
+ *
+ * ...
+ *
+ * ccnxInterestReturn_Release(&interestReturnA);
+ * ccnxInterestReturn_Release(&interestReturnB);
+ * ccnxInterestReturn_Release(&interestReturnC);
+ * }
+ * @endcode
+ */
+bool
+ccnxInterestReturn_Equals(const CCNxInterestReturn *a, const CCNxInterestReturn *b);
+
+/**
+ * Produce a null-terminated string representation of the specified instance.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate()}.
+ *
+ * @param [in] interestReturn A pointer to the instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, nul-terminated C string that must be deallocated via `parcMemory_Deallocate()`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterestReturn *interestReturn = ccnxInterestReturn_Create(...);
+ *
+ * char *string = ccnxInterestReturn_ToString(interestReturn);
+ *
+ * if (string != NULL) {
+ * printf("InterestReturn looks like: %s\n", string);
+ * parcMemory_Deallocate(string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * ccnxInterestReturn_Release(&instance);
+ * }
+ * @endcode
+ *
+ */
+char *
+ccnxInterestReturn_ToString(const CCNxInterestReturn *interestReturn);
+
+/**
+ * Assert that an instance of `CCNxInterestReturn` is valid.
+ *
+ * If the instance is not valid, terminate via {@link trapIllegalValue}
+ *
+ * Valid means the internal state of the type is consistent with its
+ * required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] interestReturn A pointer to the instance to check.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxInterestReturn *interestReturn = ccnxInterest_Create(...);
+ * ccnxInterestReturn_AssertValid(interestReturn);
+ *
+ * ...
+ *
+ * ccnxInterestReturn_Release(&instance);
+ * }
+ * @endcode
+ */
+void
+ccnxInterestReturn_AssertValid(const CCNxInterestReturn *interestReturn);
+#endif //libccnx_ccnx_InterestReturn_h
diff --git a/libccnx-common/ccnx/common/ccnx_KeyLocator.c b/libccnx-common/ccnx/common/ccnx_KeyLocator.c
new file mode 100755
index 00000000..ea61a0c1
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_KeyLocator.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/ccnx_KeyLocator.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <parc/security/parc_Key.h>
+
+struct ccnx_key_locator {
+ union {
+ PARCKey *key;
+ CCNxLink *keyLink;
+ } locator;
+ CCNxKeyLocatorType type;
+};
+
+
+static void
+_Destroy(CCNxKeyLocator **keyLocatorP)
+{
+ if (keyLocatorP != NULL) {
+ CCNxKeyLocator *keyLocator = *keyLocatorP;
+ if (ccnxKeyLocator_IsKey(keyLocator)) {
+ parcKey_Release(&keyLocator->locator.key);
+ } else if (ccnxKeyLocator_IsKeyLink(keyLocator)) {
+ ccnxLink_Release(&keyLocator->locator.keyLink);
+ } else {
+ assertTrue(0, "KeyLocator is not one of %s.", "Key or KeyLink");
+ }
+ }
+}
+
+parcObject_ExtendPARCObject(CCNxKeyLocator, _Destroy, ccnxKeyLocator_Copy, ccnxKeyLocator_ToString, ccnxKeyLocator_Equals, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(ccnxKeyLocator, CCNxKeyLocator);
+
+parcObject_ImplementRelease(ccnxKeyLocator, CCNxKeyLocator);
+
+static CCNxKeyLocator *
+_Create(void)
+{
+ CCNxKeyLocator *result = parcObject_CreateInstance(CCNxKeyLocator);
+ if (NULL != result) {
+ result->locator.key = NULL;
+ result->type = CCNxKeyLocatorType_None;
+ }
+ return result;
+}
+
+CCNxKeyLocator *
+ccnxKeyLocator_Copy(const CCNxKeyLocator *original)
+{
+ CCNxKeyLocator *copy = NULL;
+
+ switch (original->type) {
+ case CCNxKeyLocatorType_Key: {
+ PARCKey *keyCopy = parcKey_Copy(original->locator.key);
+ copy = ccnxKeyLocator_CreateFromKey(keyCopy);
+ parcKey_Release(&keyCopy);
+ }
+ break;
+
+ case CCNxKeyLocatorType_Link: {
+ CCNxLink *keyLinkCopy = ccnxLink_Copy(original->locator.keyLink);
+ copy = ccnxKeyLocator_CreateFromKeyLink(keyLinkCopy);
+ ccnxLink_Release(&keyLinkCopy);
+ }
+ break;
+
+ case CCNxKeyLocatorType_None:
+ copy = _Create();
+ break;
+ }
+ return copy;
+}
+
+CCNxKeyLocator *
+ccnxKeyLocator_CreateFromKey(PARCKey *key)
+{
+ assertNotNull(key, "Parameter must be a non-null CCNxKey pointer.");
+
+ CCNxKeyLocator *result = _Create();
+ if (result != NULL) {
+ result->locator.key = parcKey_Acquire(key);
+ result->type = CCNxKeyLocatorType_Key;
+ }
+
+ return result;
+}
+
+CCNxKeyLocator *
+ccnxKeyLocator_CreateFromKeyLink(CCNxLink *keyLink)
+{
+ CCNxKeyLocator *result = _Create();
+ if (result != NULL) {
+ result->locator.keyLink = ccnxLink_Acquire(keyLink);
+ result->type = CCNxKeyLocatorType_Link;
+ }
+
+ return result;
+}
+
+bool
+ccnxKeyLocator_Equals(const CCNxKeyLocator *a, const CCNxKeyLocator *b)
+{
+ if (a == b) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (a->type == b->type) {
+ switch (a->type) {
+ case CCNxKeyLocatorType_Key:
+ return parcKey_Equals(a->locator.key, b->locator.key);
+
+ case CCNxKeyLocatorType_Link:
+ return ccnxLink_Equals(a->locator.keyLink, b->locator.keyLink);
+
+ default:
+ break;
+ // fall through
+ }
+ }
+ return false;
+}
+
+CCNxKeyLocatorType
+ccnxKeyLocator_GetType(const CCNxKeyLocator *ccnxKeyLocator)
+{
+ assertNotNull(ccnxKeyLocator, "Parameter must be a non-null CCNxKeyLocator pointer.");
+
+ return ccnxKeyLocator->type;
+}
+
+bool
+ccnxKeyLocator_IsKey(const CCNxKeyLocator *keyLocator)
+{
+ return (keyLocator->type == CCNxKeyLocatorType_Key);
+}
+
+bool
+ccnxKeyLocator_IsKeyLink(const CCNxKeyLocator *keyLocator)
+{
+ return (keyLocator->type == CCNxKeyLocatorType_Link);
+}
+
+char *
+ccnxKeyLocator_ToString(const CCNxKeyLocator *keyLocator)
+{
+ char *result;
+
+ if (keyLocator == NULL) {
+ char *nullString = "NULL";
+ result = parcMemory_StringDuplicate(nullString, strlen(nullString));
+ } else {
+ char *locator;
+ if (ccnxKeyLocator_IsKey(keyLocator)) {
+ locator = parcKey_ToString(keyLocator->locator.key);
+ } else if (ccnxKeyLocator_IsKeyLink(keyLocator)) {
+ locator = ccnxLink_ToString(keyLocator->locator.keyLink);
+ } else {
+ char *initString = "not initialised.";
+ locator = parcMemory_StringDuplicate(initString, strlen(initString));
+ }
+ char *string;
+ int failure = asprintf(&string, "KeyLocator { %s }", locator);
+ assertTrue(failure > -1, "Error asprintf");
+
+ parcMemory_Deallocate((void **) &locator);
+
+ result = parcMemory_StringDuplicate(string, strlen(string));
+ free(string);
+ }
+
+ return result;
+}
+
+CCNxLink *
+ccnxKeyLocator_GetKeyLink(const CCNxKeyLocator *keyLocator)
+{
+ assertTrue(keyLocator->type == CCNxKeyLocatorType_Link, "Key Locator must be of type CCNxKeyLocatorType_Link");
+
+ if (keyLocator->type == CCNxKeyLocatorType_Link) {
+ return keyLocator->locator.keyLink;
+ }
+ return NULL;
+}
+
+PARCKey *
+ccnxKeyLocator_GetKey(const CCNxKeyLocator *keyLocator)
+{
+ assertTrue(keyLocator->type == CCNxKeyLocatorType_Key, "Key Locator must be of type CCNxKeyLocatorType_Key");
+
+ if (keyLocator->type == CCNxKeyLocatorType_Key) {
+ return keyLocator->locator.key;
+ }
+ return NULL;
+}
+
+void
+ccnxKeyLocator_AssertValid(const CCNxKeyLocator *keyLocator)
+{
+ assertNotNull(keyLocator, "CCNxKeyLocator pointer was null");
+ if (ccnxKeyLocator_IsKey(keyLocator)) {
+ parcKey_AssertValid(keyLocator->locator.key);
+ } else if (ccnxKeyLocator_IsKeyLink(keyLocator)) {
+ ccnxLink_AssertValid(keyLocator->locator.keyLink);
+ } else {
+ assertTrue(0, "KeyLocator is not one of %s.", "Key or Key Link");
+ }
+}
diff --git a/libccnx-common/ccnx/common/ccnx_KeyLocator.h b/libccnx-common/ccnx/common/ccnx_KeyLocator.h
new file mode 100755
index 00000000..e48b80a7
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_KeyLocator.h
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_KeyLocator.h
+ * @ingroup Signature
+ * @brief A `CCNxKeyLocator` encapsulates the information and/or data necessary to retrieve a `PARCKey`.
+ *
+ * There are at least two ways in which a `PARCKey` can be instantiated:
+ *
+ * (1) By embedding and subsequently extracting the raw key data in a message, and
+ * (2) By specifying a link for a key so that an interest can be issued to obtain the key content
+ *
+ * A key locator encapsulates both methods. The API provides functions to create key locators
+ * for each key retrieval type and use them to retrieve `PARCKey` methods.
+ *
+ */
+#ifndef libccnx_ccnx_KeyLocator_h
+#define libccnx_ccnx_KeyLocator_h
+
+#include <stdbool.h>
+
+#include <ccnx/common/ccnx_Link.h>
+
+#include <parc/security/parc_Key.h>
+
+/**
+ * @typedef CCNxKeyLocatorType
+ * @brief Locator types for finding keys.
+ */
+typedef enum {
+ CCNxKeyLocatorType_None = 0,
+ CCNxKeyLocatorType_Link = 1,
+ CCNxKeyLocatorType_Key = 2
+} CCNxKeyLocatorType;
+
+struct ccnx_key_locator;
+
+/**
+ * @typedef CCNxKeyLocator
+ * @brief A `CCNxKeyLocator` encapsulates the information and/or data necessary to retrieve a {@link PARCKey}.
+ */
+typedef struct ccnx_key_locator CCNxKeyLocator;
+
+/**
+ * Create a `CCNxKeyLocator` instance from a {@link PARCKey} instance.
+ *
+ * @param [in] key The `PARCKey` instance which is used to construct the `CCNxKeyLocator` instance.
+ *
+ * @return `CCNxKeyLocator` A new `CCNxKeyLocator` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKey *key = ...
+ * CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKey(key);
+ * // use the keyLocator instance
+ * }
+ * @endcode
+ */
+CCNxKeyLocator *ccnxKeyLocator_CreateFromKey(PARCKey *key);
+
+/**
+ * Create a `CCNxKeyLocator` instance from a {@link CCNxName} instance.
+ *
+ * @param [in] keyLink The `CCNxLink` instance used to create the `CCNxKeyLocator` instance
+ *
+ * @return `CCNxKeyLocator` A new `CCNxKeyLocator` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci//name");
+ * CCNxLink *keyURILink = ccnxLink_Create(name, NULL, NULL);
+ *
+ * CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyURILink);
+ * // use the keyLocator instance
+ * }
+ * @endcode
+ */
+CCNxKeyLocator *ccnxKeyLocator_CreateFromKeyLink(CCNxLink *keyLink);
+
+/**
+ * Retrieve the {@link CCNxKeyLocatorType} associated with this `CCNxKeyLocator`.
+ *
+ * The locator type will specify one of the three methods used to obtain a
+ * PARCKey: (1) embedded keys, (2) certificates, or (3) key (content) names.
+ *
+ * @param [in] keyLocator The `CCNxKeyLocator` instance from which the location
+ * type is retrieved.
+ *
+ * @return A `CCNxKeyLocatorType` value.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxLink_Create("lci//name");
+ * CCNxLink *keyURILink = ccnxName_CreateFromCString(name, NULL, NULL);
+ *
+ * CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyURILink);
+ * CCNxKeyLocatorType locatorType = ccnxKeyLocator_GetType(keyLocator);
+ * // use the locator type
+ * }
+ * @endcode
+ */
+CCNxKeyLocatorType ccnxKeyLocator_GetType(const CCNxKeyLocator *keyLocator);
+
+/**
+ * Determine if the key locator type is type `CCNxKeyLocatorType_Key`.
+ *
+ * @param [in] keyLocator `CCNxKeyLocator` instance being examined.
+ *
+ * @return true If the key locator type is type `CCNxKeyLocatorType_Key`
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * PARCKey *key = ...
+ * CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKey(key);
+ * bool isKeyType = ccnxKeyLocator_IsKey(keyLocator);
+ * // isKeyType will be true
+ * }
+ * @endcode
+ */
+bool ccnxKeyLocator_IsKey(const CCNxKeyLocator *keyLocator);
+
+/**
+ * Determine if the key locator type is type `CCNxKeyLocatorType_Link`.
+ *
+ * @param [in] keyLocator `CCNxKeyLocator` instance being examined.
+ *
+ * @return true If the key locator type is type `CCNxKeyLocatorType_Link`
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ * CCNxLink *keyURILink = ccnxLink_Create(name, NULL, NULL);
+ * CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyURILink);
+ * bool isKeyNameType = ccnxKeyLocator_IsKeyLink(keyLocator);
+ * // isKeyNameType will be true
+ * }
+ * @endcode
+ */
+bool ccnxKeyLocator_IsKeyLink(const CCNxKeyLocator *keyLocator);
+
+/**
+ * Produce a null-terminated C-string representation of the specified instance.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to the instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A null-terminated string that must be deallocated via `parcMemory_Deallocate`.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ * CCNxKeyLocator *keyLocator = ccnxKeyLocator_FromKeyName(name);
+ * char *stringRep = ccnxKeyLocator_ToString(keyLocator);
+ * }
+ * @endcode
+ */
+char *ccnxKeyLocator_ToString(const CCNxKeyLocator *instance);
+
+/**
+ * Retrieve the {@link CCNxLink} instance from the specified `CCNxKeyLocator` instance.
+ *
+ * The type of the key locator must be `CCNxKeyLocatorType_Link` prior to invocation,
+ * else a trap will be invoked.
+ *
+ * @param [in] keyLocator The `CCNxKeyLocator` from which the name is extracted.
+ *
+ * @return A non-NULL `CCNxName` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_Create("lci//name");
+ * CCNxLink *keyURILink = ccnxLink_CreateFromURI(name, NULL, NULL);
+ *
+ * CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyURILink);
+ * CCNxLink *copy = ccnxKeyLocator_GetKeyLink(keyLocator);
+ * // use the link copy
+ * }
+ * @endcode
+ */
+CCNxLink *ccnxKeyLocator_GetKeyLink(const CCNxKeyLocator *keyLocator);
+
+/**
+ * Retrieve the {@link PARCKey} instance from the specified `CCNxKeyLocator` instance.
+ *
+ * The type of the key locator must be `CCNxKeyLocatorType_Key` prior to invocation,
+ * else a trap will be invoked.
+ *
+ * @param [in] keyLocator The `CCNxKeyLocator` from which the key is extracted.
+ *
+ * @return A non-NULL `PARCKey` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKey *key = ...;
+ * CCNxKeyLocator *keyLocator = ccnxKeyLocator_FromKey(key);
+ * CCNxKey *copy = ccnxKeyLocator_GetKey(keyLocator);
+ * // use the key copy
+ * }
+ * @endcode
+ */
+PARCKey *ccnxKeyLocator_GetKey(const CCNxKeyLocator *keyLocator);
+
+/**
+ * Determine if two `CCNxKeyLocators` are equal.
+ *
+ * The following equivalence relations on non-null `CCNxKeyLocator` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `ccnxKeyLocator_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxKeyLocator_Equals(x, y)` must return true if and only if
+ * `ccnxKeyLocator_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxKeyLocator_Equals(x, y)` returns true and
+ * `ccnxKeyLocator_Equals(y, z)` returns true,
+ * then `ccnxKeyLocator_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxKeyLocator_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxKeyLocator_Equals(x, NULL)` must return false.
+ *
+ * @param a A pointer to a `CCNxKeyLocator` instance.
+ * @param b A pointer to a `CCNxKeyLocator` instance.
+ * @return True if the referenced `CCNxKeyLocators` are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name1 = ccnxLink_Create("lci//name");
+ * CCNxLink *keyURILink1 = ccnxName_CreateFromCString(name1, NULL, NULL);
+ *
+ * CCNxKeyLocator *keyLocator1 = ccnxKeyLocator_FromKeyName(keyURILink1);
+ *
+ * CCNxName *name2 = ccnxLink_Create("lci//name");
+ * CCNxLink *keyURILink2 = ccnxName_CreateFromCString(name2, NULL, NULL);
+ *
+ * CCNxKeyLocator *keyLocator2 = ccnxKeyLocator_FromKeyName(keyURILink2);
+ *
+ * if (ccnxKeyLocator_Equals(keyLocator1, keyLocator2)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool ccnxKeyLocator_Equals(const CCNxKeyLocator *a, const CCNxKeyLocator *b);
+
+/**
+ * Create a copy of the given `CCNxKeyLocator` instance.
+ *
+ * This creates a deep copy of the `CCNxKeyLocator` instance, acquiring handles to internal object
+ * references when needed.
+ *
+ * @param [in] original The `CCNxKeyLocator` instance which is being copied
+ *
+ * @return `CCNxKeyLocator` A copy of the specified `CCNxKeyLocator`
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name");
+ * CCNxKeyLocator *keyLocator = ccnxKeyLocator_FromKeyName(keyURIName);
+ * CCNxKeyLocator *copy = ccnxKeyLocator_Copy(keyLocator);
+ * // use the copied instance
+ * }
+ * @endcode
+ */
+CCNxKeyLocator *ccnxKeyLocator_Copy(const CCNxKeyLocator *original);
+
+/**
+ * Increase the number of references to a `CCNxKeyLocator`.
+ *
+ * Note that new `CCNxKeyLocator` is not created,
+ * only that the given `CCNxKeyLocator` reference count is incremented.
+ * Discard the reference by invoking {@link ccnxKeyLocator_Release}.
+ *
+ * @param instance A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxKeyLocator *keyLocator = ccnxKeyLocator_Acquire(instance);
+ *
+ * ccnxKeyLocator_Release(&keyLocator);
+ *
+ * }
+ * @endcode
+ *
+ * @see `ccnxKeyLocator_Release`
+ */
+CCNxKeyLocator *ccnxKeyLocator_Acquire(const CCNxKeyLocator *instance);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] object A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxKeyLocator *cert = ccnxKeyLocator_Acquire(instance);
+ *
+ * ccnxKeyLocator_Release(&cert);
+ *
+ * }
+ * @endcode
+ */
+void ccnxKeyLocator_Release(CCNxKeyLocator **object);
+
+#ifdef Libccnx_DISABLE_VALIDATION
+# define ccnxKeyLocator_OptionalAssertValid(_instance_)
+#else
+# define ccnxKeyLocator_OptionalAssertValid(_instance_) ccnxKeyLocator_AssertValid(_instance_)
+#endif
+/**
+ * Check that the pointer to the `KeyLocator` is valid. It should be non-null,
+ * and any required referenced data should be valid.
+ *
+ * @param [in] object A pointer to the instance to check.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * ccnxKeyLocator_AssertValid(keyLocator);
+ *
+ * }
+ * @endcode
+ */
+void ccnxKeyLocator_AssertValid(const CCNxKeyLocator *object);
+#endif // libccnx_ccnx_KeyLocator_h
diff --git a/libccnx-common/ccnx/common/ccnx_KeystoreUtilities.c b/libccnx-common/ccnx/common/ccnx_KeystoreUtilities.c
new file mode 100755
index 00000000..1ae94ef6
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_KeystoreUtilities.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+
+#include <pwd.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <sys/stat.h>
+
+#include <sys/param.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <ccnx/common/ccnx_KeystoreUtilities.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Signer.h>
+
+
+struct keystore_params {
+ char filename[1024];
+ char password[1024];
+ PARCSigner *signer;
+};
+
+#define OPT_KEYSTORE 'k'
+#define OPT_PASSWORD 'p'
+#define OPT_BITS 'b'
+#define OPT_DAYS 'y'
+
+static const char *emptyPassword = "";
+
+static char *
+ccnxKeystoreUtilities_ConstructPath(const char *dir, const char *file)
+{
+ char *path = parcMemory_AllocateAndClear(MAXPATHLEN);
+ assertNotNull(path, "parcMemory_AllocateAndClear(%u) returned NULL", MAXPATHLEN);
+ strncpy(path, dir, MAXPATHLEN);
+ strncat(path, "/", MAXPATHLEN);
+ strncat(path, file, MAXPATHLEN);
+ return path;
+}
+
+static char *
+ccnxKeystoreUtilities_HomeDirectoryFromEnv()
+{
+ char *home = getenv("HOME");
+ if (home != NULL) {
+ home = parcMemory_StringDuplicate(home, strlen(home) + 1);
+ }
+ return home;
+}
+
+static char *
+ccnxKeystoreUtilities_HomeDirectoryFromPasswd()
+{
+ struct passwd *pw = getpwuid(getuid());
+ const char *homedir = pw->pw_dir;
+ return parcMemory_StringDuplicate(homedir, strlen(homedir) + 1);
+}
+
+static KeystoreParams *
+ccnxKeystoreUtilities_OpenFromPath(const char *path, const char *password)
+{
+ KeystoreParams *params = NULL;
+
+ // If the file exists, try to open it as a keystore
+ struct stat filestat;
+ int failure = stat(path, &filestat);
+ if (!failure) {
+ PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(path, password, PARCCryptoHashType_SHA256);
+ PARCKeyStore *publicKeyStore = parcKeyStore_Create(keyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&keyStore);
+ PARCPublicKeySigner *pksigner = parcPublicKeySigner_Create(publicKeyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(pksigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&pksigner);
+
+ if (signer) {
+ params = ccnxKeystoreUtilities_Create(signer, path, password);
+
+ parcSigner_Release(&signer);
+ parcKeyStore_Release(&publicKeyStore);
+ }
+ }
+
+ return params;
+}
+
+static KeystoreParams *
+ccnxKeystoreUtilities_CreateInPath(const char *path, const char *password, int keystoreBits, int keystoreDays)
+{
+ KeystoreParams *params = NULL;
+
+ bool success = parcPkcs12KeyStore_CreateFile(path, password, "ccnxuser", keystoreBits, keystoreDays);
+ if (success) {
+ PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(path, password, PARCCryptoHashType_SHA256);
+ PARCKeyStore *publicKeyStore = parcKeyStore_Create(keyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&keyStore);
+ PARCPublicKeySigner *pksigner = parcPublicKeySigner_Create(publicKeyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(pksigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&pksigner);
+
+ if (signer) {
+ params = ccnxKeystoreUtilities_Create(signer, path, password);
+
+ parcSigner_Release(&signer);
+ parcKeyStore_Release(&publicKeyStore);
+ }
+ }
+ return params;
+}
+
+
+static char *
+ccnxKeystoreUtilities_GetHomeDirectory()
+{
+ char *homedir = ccnxKeystoreUtilities_HomeDirectoryFromEnv();
+ if (homedir == NULL) {
+ homedir = ccnxKeystoreUtilities_HomeDirectoryFromPasswd();
+ }
+ return homedir;
+}
+
+static KeystoreParams *
+ccnxKeystoreUtilities_OpenFromHomeDirectory(const char *password)
+{
+ KeystoreParams *params = NULL;
+
+ char *homedir = ccnxKeystoreUtilities_GetHomeDirectory();
+ char *ccnxdir = ccnxKeystoreUtilities_ConstructPath(homedir, ".ccnx");
+
+
+ char *path = ccnxKeystoreUtilities_ConstructPath(ccnxdir, ".ccnx_keystore.p12");
+ params = ccnxKeystoreUtilities_OpenFromPath(path, password);
+ parcMemory_Deallocate((void **) &path);
+
+ if (params == NULL) {
+ // try the older filename
+ char *path = ccnxKeystoreUtilities_ConstructPath(ccnxdir, ".ccnx_keystore");
+ params = ccnxKeystoreUtilities_OpenFromPath(path, password);
+ parcMemory_Deallocate((void **) &path);
+ }
+
+ parcMemory_Deallocate((void **) &ccnxdir);
+ parcMemory_Deallocate((void **) &homedir);
+ return params;
+}
+
+static KeystoreParams *
+ccnxKeystoreUtilities_CreateInHomeDirectory(const char *keystorePassword, int keystoreBits, int keystoreDays)
+{
+ char *homedir = ccnxKeystoreUtilities_GetHomeDirectory();
+ char *ccnxdir = ccnxKeystoreUtilities_ConstructPath(homedir, ".ccnx");
+ // Needs to check the return value to ensure that it was created. See case 1003.
+ mkdir(ccnxdir, 0700);
+
+ char *path = ccnxKeystoreUtilities_ConstructPath(ccnxdir, ".ccnx_keystore.p12");
+ KeystoreParams *params = ccnxKeystoreUtilities_CreateInPath(path, keystorePassword, keystoreBits, keystoreDays);
+
+ parcMemory_Deallocate((void **) &path);
+ parcMemory_Deallocate((void **) &ccnxdir);
+ parcMemory_Deallocate((void **) &homedir);
+ return params;
+}
+
+#ifdef _ANDROID_
+static char *
+getpass(const char *prompt)
+{
+ trapNotImplemented("getpass() is not implemented on Android. See BugzId: 3864");
+}
+#endif
+
+/**
+ * Read a password, then zero the static memory
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return An allocated string, use <code>parcMemory_Deallocate()</code> on it.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static char *
+_readPassword(const char *prompt)
+{
+ char *staticBuffer = getpass(prompt);
+ char *password = parcMemory_StringDuplicate(staticBuffer, strlen(staticBuffer) + 1);
+ memset(staticBuffer, 0, strlen(staticBuffer));
+ return password;
+}
+
+KeystoreParams *
+ccnxKeystoreUtilities_OpenFile(const char *keystoreFile, const char *keystorePassword)
+{
+ if (keystorePassword == NULL) {
+ keystorePassword = emptyPassword;
+ }
+
+ KeystoreParams *params = NULL;
+
+ if (keystoreFile == NULL) {
+ params = ccnxKeystoreUtilities_OpenFromHomeDirectory(keystorePassword);
+ } else {
+ params = ccnxKeystoreUtilities_OpenFromPath(keystoreFile, keystorePassword);
+ }
+
+ return params;
+}
+
+KeystoreParams *
+ccnxKeystoreUtilities_CreateFile(const char *keystoreFile, const char *keystorePassword, int keystoreBits, int keystoreDays)
+{
+ if (keystorePassword == NULL) {
+ keystorePassword = emptyPassword;
+ }
+
+ KeystoreParams *params = NULL;
+
+ if (keystoreFile == NULL) {
+ params = ccnxKeystoreUtilities_CreateInHomeDirectory(keystorePassword, keystoreBits, keystoreDays);
+ } else {
+ params = ccnxKeystoreUtilities_CreateInPath(keystoreFile, keystorePassword, keystoreBits, keystoreDays);
+ }
+
+ return params;
+}
+
+KeystoreParams *
+ccnxKeystoreUtilities_Create(PARCSigner *signer, const char *path, const char *password)
+{
+ KeystoreParams *params = parcMemory_AllocateAndClear(sizeof(KeystoreParams));
+ assertNotNull(params, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(KeystoreParams));
+ params->signer = parcSigner_Acquire(signer);
+ strncpy(params->filename, path, 1024);
+ strncpy(params->password, password, 1024);
+ return params;
+}
+
+void
+keystoreParams_Destroy(KeystoreParams **paramsPtr)
+{
+ KeystoreParams *params = *paramsPtr;
+ if (params->signer != NULL) {
+ parcSigner_Release(&params->signer);
+ }
+ parcMemory_Deallocate((void **) &params);
+ *paramsPtr = NULL;
+}
+
+char *
+ccnxKeystoreUtilities_ReadPassword(void)
+{
+ return _readPassword("Password: ");
+}
+
+bool
+ccnxKeystoreUtilities_ConfirmPassword(const char *mustEqualPassword)
+{
+ bool equals = false;
+
+ char *b = _readPassword("Confirm : ");
+ if (strcmp(mustEqualPassword, b) == 0) {
+ equals = true;
+ }
+
+ memset(b, 0, strlen(b));
+ parcMemory_Deallocate((void **) &b);
+ return equals;
+}
+
+const char *
+ccnxKeystoreUtilities_GetFileName(const KeystoreParams *params)
+{
+ return params->filename;
+}
+
+const char *
+ccnxKeystoreUtilities_GetPassword(const KeystoreParams *params)
+{
+ return params->password;
+}
diff --git a/libccnx-common/ccnx/common/ccnx_KeystoreUtilities.h b/libccnx-common/ccnx/common/ccnx_KeystoreUtilities.h
new file mode 100755
index 00000000..20d733cd
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_KeystoreUtilities.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_KeystoreUtilities.h
+ * @ingroup Signature
+ * @brief A set of tools for working with the CCNx keystore.
+ *
+ */
+#ifndef libccnx_ccnx_KeystoreUtilities_h
+#define libccnx_ccnx_KeystoreUtilities_h
+
+#include <parc/security/parc_Signer.h>
+
+struct keystore_params;
+/**
+ * @typedef KeystoreParams
+ * @brief Parameters for the KeyStore.
+ */
+
+typedef struct keystore_params KeystoreParams;
+
+/**
+ * Create a new `KeystoreParams` from a @p path, @p password, and a {@link PARCSigner}.
+ *
+ * @param [in] signer A pointer to an instance of `PARCSigner`.
+ * @param [in] path The path to use.
+ * @param [in] password The password to use.
+ *
+ * @return A pointer to a new instance of `KeystoreParams`.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+KeystoreParams *ccnxKeystoreUtilities_Create(PARCSigner *signer, const char *path, const char *password);
+
+/**
+ * Destroy the `KeystoreParams`.
+ *
+ * @param [in,out] paramsPtr A pointer to the pointer to the `KeystoreParams` to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+void keystoreParams_Destroy(KeystoreParams **paramsPtr);
+
+/**
+ * Opens a PKCS12 keystore for use with CCNx, or creates it if missing.
+ *
+ * All options may be NULL.
+ * keystoreFile is the filename and path to use. If the option is omitted, then the default location is used.
+ * The default location is in ~/.ccnx/.ccnx_keystore.p12, which is a PKCS12 keystore. For compatability
+ * with older implementations, will also look for ~/.ccnx/.ccnx_keystore without the file extension.
+ * keystorePassword is the password to use. If missing, will prompt with getpass(3).
+ *
+ * This function uses the equivalent of getopt_long(3). It does not change the argv.
+ *
+ * @param [in] keystoreFile The full path to the keystore, may be NULL to use ~/.ccnx/.ccnx_keystore.p12
+ * @param [in] keystorePassword The keystore password, may be NULL for no password.
+ * @return The `KeystoreParams`, including the path used, password used, and the `PARCSigner`, NULL if cannot be opened.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+KeystoreParams *ccnxKeystoreUtilities_OpenFile(const char *keystoreFile, const char *keystorePassword);
+
+/**
+ * Creates a PKCS12 keystore.
+ *
+ * @param [in] keystoreFile may be NULL to use the default location
+ * @param [in] keystorePassword The keystore password, may be NULL for no password.
+ * @param [in] keystoreBits The keystore bits, may be NULL for no password.
+ * @param [in] keystoreDays The keystore days, may be NULL for no password.
+ * @return The keystore parameters, including the path used, password used, and the `PARCSigner`, NULL if cannot be created.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+KeystoreParams *ccnxKeystoreUtilities_CreateFile(const char *keystoreFile, const char *keystorePassword, int keystoreBits, int keystoreDays);
+
+/**
+ * Returns an allocated buffer with password
+ *
+ * Reads a password from stdin, then scrubs the static memory
+ *
+ * @return Free with {@link parcMemory_Deallocate()}
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+char *ccnxKeystoreUtilities_ReadPassword(void);
+
+/**
+ * Returns an allocated buffer with password
+ *
+ * Reads a password from stdin, then scrubs the static memory.
+ * Confirms that it equals the provided password.
+ *
+ * @param [in] mustEqualPassword The password that must match.
+ *
+ * @return `true` if the password from stdin matches.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxKeystoreUtilities_ConfirmPassword(const char *mustEqualPassword);
+
+/**
+ * Get the file name from the given {@link KeystoreParams} instance.
+ *
+ * @param [in] params A pointer to a valid `KeystoreParams` instance.
+ *
+ * @return A pointer to a null-terminated C string containing the file name.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+const char *ccnxKeystoreUtilities_GetFileName(const KeystoreParams *params);
+
+/**
+ * Get the password from the given `KeyStoreParams` instance.
+ *
+ * @param [in] params A pointer to a valid `KeystoreParams` instance.
+ *
+ * @return A pointer to a null-terminated C string containing the password.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+const char *ccnxKeystoreUtilities_GetPassword(const KeystoreParams *params);
+#endif // libccnx_ccnx_KeystoreUtilities_h
diff --git a/libccnx-common/ccnx/common/ccnx_Link.c b/libccnx-common/ccnx/common/ccnx_Link.c
new file mode 100755
index 00000000..ce1ee68f
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_Link.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <ccnx/common/ccnx_Link.h>
+
+#include <parc/algol/parc_Object.h>
+
+struct ccnx_link {
+ const CCNxName *name;
+ PARCBuffer *keyId;
+ PARCBuffer *contentHash;
+};
+
+static void
+_destroy(CCNxLink **linkP)
+{
+ ccnxName_Release((CCNxName **) &(*linkP)->name);
+ if ((*linkP)->keyId != NULL) {
+ parcBuffer_Release(&(*linkP)->keyId);
+ }
+ if ((*linkP)->contentHash != NULL) {
+ parcBuffer_Release(&(*linkP)->contentHash);
+ }
+}
+
+parcObject_ExtendPARCObject(CCNxLink, _destroy, NULL, ccnxLink_ToString, ccnxLink_Equals, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(ccnxLink, CCNxLink);
+
+parcObject_ImplementRelease(ccnxLink, CCNxLink);
+
+CCNxLink *
+ccnxLink_Create(const CCNxName *name, PARCBuffer *keyId, PARCBuffer *contentObjectHash)
+{
+ CCNxLink *link = parcObject_CreateInstance(CCNxLink);
+
+ if (link != NULL) {
+ link->name = ccnxName_Acquire(name);
+ link->keyId = (keyId == NULL) ? NULL : parcBuffer_Acquire(keyId);
+ link->contentHash = (contentObjectHash == NULL) ? NULL : parcBuffer_Acquire(contentObjectHash);
+ }
+
+ return link;
+}
+
+CCNxLink *
+ccnxLink_Copy(const CCNxLink *original)
+{
+ CCNxLink *link = parcObject_CreateInstance(CCNxLink);
+
+ if (link != NULL) {
+ link->name = ccnxName_Copy(original->name);
+ link->keyId = (original->keyId == NULL) ? NULL : parcBuffer_Copy(original->keyId);
+ link->contentHash = (original->contentHash == NULL) ? NULL : parcBuffer_Copy(original->contentHash);
+ }
+
+ return link;
+}
+
+const CCNxName *
+ccnxLink_GetName(const CCNxLink *link)
+{
+ return link->name;
+}
+
+PARCBuffer *
+ccnxLink_GetKeyID(const CCNxLink *link)
+{
+ return link->keyId;
+}
+
+PARCBuffer *
+ccnxLink_GetContentObjectHash(const CCNxLink *link)
+{
+ return link->contentHash;
+}
+
+bool
+ccnxLink_Equals(const CCNxLink *objectA, const CCNxLink *objectB)
+{
+ bool result = false;
+
+ if (objectA == objectB) {
+ result = true;
+ } else if (objectA != NULL && objectB != NULL) {
+ if (ccnxName_Equals(objectA->name, objectB->name)) {
+ if (parcBuffer_Equals(objectA->keyId, objectB->keyId)) {
+ if (parcBuffer_Equals(objectA->contentHash, objectB->contentHash)) {
+ return true;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+char *
+ccnxLink_ToString(const CCNxLink *link)
+{
+ char *nameString = ccnxName_ToString(link->name);
+ char *keyIdString = "NULL";
+ bool nullKeyIdString = true;
+
+ if (link->keyId != NULL) {
+ keyIdString = parcBuffer_ToString(link->keyId);
+ nullKeyIdString = false;
+ }
+
+ char *contentObjectHashString = NULL;
+ bool nullContentObjectHashString = true;
+ if (link->contentHash != NULL) {
+ contentObjectHashString = parcBuffer_ToString(link->contentHash);
+ nullContentObjectHashString = false;
+ }
+
+ char *string;
+ int failure = asprintf(&string, "CCNxLink { .name=\"%s\", .KeyID=\"%s\", .ContentObjectHash=\"%s\" }",
+ nameString,
+ keyIdString,
+ contentObjectHashString);
+ assertTrue(failure > -1, "Error asprintf");
+
+ parcMemory_Deallocate((void **) &nameString);
+ if (!nullKeyIdString) {
+ parcMemory_Deallocate((void **) &keyIdString);
+ }
+ if (!nullContentObjectHashString) {
+ parcMemory_Deallocate((void **) &contentObjectHashString);
+ }
+
+ char *result = parcMemory_StringDuplicate(string, strlen(string));
+ free(string);
+
+ return result;
+}
+
+bool
+ccnxLink_IsValid(const CCNxLink *link)
+{
+ bool result = false;
+
+ if (link != NULL) {
+ if (ccnxName_IsValid(link->name)) {
+ if (link->keyId == NULL || parcBuffer_IsValid(link->keyId)) {
+ if (link->contentHash == NULL || parcBuffer_IsValid(link->contentHash)) {
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+void
+ccnxLink_AssertValid(const CCNxLink *link)
+{
+ assertTrue(ccnxLink_IsValid(link), "CCNxLink instance is not valid.");
+}
diff --git a/libccnx-common/ccnx/common/ccnx_Link.h b/libccnx-common/ccnx/common/ccnx_Link.h
new file mode 100755
index 00000000..cd2b62ff
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_Link.h
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_Link.h
+ * @ingroup ContentObject
+ * @brief A generic CCNx link that contains a hash, name, KeyID.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#ifndef libccnx_ccnx_Link_h
+#define libccnx_ccnx_Link_h
+
+#include <ccnx/common/ccnx_Name.h>
+
+#include <parc/security/parc_Signature.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+struct ccnx_link;
+
+/**
+ * @typedef CCNxLink
+ * @brief A generic CCNx link that contains a hash, name, KeyID.
+ * @see {@link ccnxLink_Create}
+ */
+typedef struct ccnx_link CCNxLink;
+
+/**
+ * Create a new `CCNxLink` instance.
+ *
+ * @param [in] name The {@link CCNxName} for the new `CCNxLink`.
+ * @param [in] keyId A {@link PARCBuffer} containing the KeyID for the new `CCNxLink`.
+ * @param [in] contentObjectHash A `PARCBuffer` containing the Content Object Hash for the new `CCNxLink`.
+ * @return A pointer to a new `CCNxLink` instance, or NULL if an error or out of memory.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxLink *ccnxLink_Create(const CCNxName *name, PARCBuffer *keyId, PARCBuffer *contentObjectHash);
+
+/**
+ * Create a new `CCNxLink` instance as a copy of the original.
+ *
+ * @param [in] original The {@link CCNxLink} to copy.
+ * @return A pointer to a new `CCNxLink` instance, or NULL if an error or out of memory.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxLink *ccnxLink_Copy(const CCNxLink *original);
+
+/**
+ * Fetch the name associated with this `CCNxLink`.
+ *
+ * @param [in] link A pointer to a `CCNxLink` instance
+ * @return The {@link CCNxName} associated with the @p link.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const CCNxName *ccnxLink_GetName(const CCNxLink *link);
+
+/**
+ * Fetch the KeyID associated with this `CCNxLink`.
+ *
+ * @param [in] link A pointer to a `CCNxLink` instance
+ * @return a {@link PARCBuffer} containing the KeyID associated with the @p link.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *ccnxLink_GetKeyID(const CCNxLink *link);
+
+/**
+ * Fetch the ContentObjectHash associated with this `CCNxLink`.
+ *
+ * @param [in] link A pointer to a `CCNxLink` instance
+ * @return a {@link PARCBuffer} containing the Content Object Hash associated with the @p link.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *ccnxLink_GetContentObjectHash(const CCNxLink *link);
+
+/**
+ * Determine if two `CCNxLink` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxLink` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `ccnxLink_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxLink_Equals(x, y)` must return true if and only if
+ * `ccnxLink_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxLink_Equals(x, y)` returns true and
+ * `ccnxLink_Equals(y, z)` returns true,
+ * then `ccnxLink_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxLink_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxLink_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] x A pointer to a `CCNxLink` instance.
+ * @param [in] y A pointer to a `CCNxLink` instance.
+ * @return `true` if the referenced `CCNxLink` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxLink *a = ccnxLink_Create();
+ * CCNxLink *b = ccnxLink_Create();
+ *
+ * if (ccnxLink_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool ccnxLink_Equals(const CCNxLink *x, const CCNxLink *y);
+
+/**
+ * Create a null-terminated string representation of the given `CCNxLink`.
+ *
+ * The returned value must be freed by the caller using {@link parcMemory_Deallocate()}.
+ *
+ * @param [in] link A pointer to a `CCNxLink` instance.
+ * @return A pointer to null-terminated string of characters that must be freed by the caller by `parcMemory_Deallocate()`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+char *ccnxLink_ToString(const CCNxLink *link);
+
+/**
+ * Increase the number of references to an instance of this object.
+ *
+ * Note that new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the reference by invoking {@link ccnxLink_Release()}.
+ *
+ * @param [in] link A pointer to a `CCNxLink` instance to acquire.
+ * @return The value of the input parameter @p link.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxLink *link = ccnxLink_Acquire(instance);
+ *
+ * ccnxLink_Release(&link);
+ *
+ * }
+ * @endcode
+ *
+ * @see ccnxLink_Release
+ */
+CCNxLink *ccnxLink_Acquire(const CCNxLink *link);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] linkP A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxLink *link = ccnxLink_Acquire(instance);
+ *
+ * ccnxLink_Release(&link);
+ *
+ * }
+ * @endcode
+ */
+void ccnxLink_Release(CCNxLink **linkP);
+
+/**
+ * Check that the pointer to the `CCNxLink` is valid. It should be non-null,
+ * and any referenced data should also be valid.
+ *
+ * @param [in] link A pointer to a `CCNxLink` instance
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxLink *link = ccnxLink_Acquire(instance);
+ *
+ * ccnxLink_AssertValid(link);
+ *
+ * }
+ * @endcode
+ */
+void ccnxLink_AssertValid(const CCNxLink *link);
+
+/**
+ * Determine if a `CCNxLink` instance is valid.
+ *
+ * @param [in] link A pointer to a `CCNxLink` instance
+ * @return true The instance is valid.
+ * @return false The instance is invalid.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxLink *link = ccnxLink_Acquire(instance);
+ *
+ * ccnxLink_AssertValid(link);
+ *
+ * }
+ * @endcode
+ */
+bool ccnxLink_IsValid(const CCNxLink *link);
+#endif // libccnx_ccnx_Link_h
diff --git a/libccnx-common/ccnx/common/ccnx_Manifest.c b/libccnx-common/ccnx/common/ccnx_Manifest.c
new file mode 100755
index 00000000..6690e5d7
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_Manifest.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+
+#include <ccnx/common/ccnx_Manifest.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+
+static const CCNxManifestInterface *_defaultImplementation = &CCNxManifestFacadeV1_Interface;
+
+static CCNxManifest *
+_ccnxManifest_InternalCreate(const CCNxManifestInterface *impl, const CCNxName *name)
+{
+ CCNxManifest *result = NULL;
+
+ if (impl->create != NULL) {
+ result = impl->create(name);
+
+ // And set the dictionary's interface pointer to the one we just used to create this.
+ ccnxTlvDictionary_SetMessageInterface(result, impl);
+ } else {
+ trapNotImplemented("Manifest implementations must implement create()");
+ }
+
+ return result;
+}
+
+parcObject_ImplementAcquire(ccnxManifest, CCNxManifest);
+parcObject_ImplementRelease(ccnxManifest, CCNxManifest);
+
+CCNxManifest *
+ccnxManifest_Create(const CCNxName *name)
+{
+ return _ccnxManifest_InternalCreate(_defaultImplementation, name);
+}
+
+CCNxManifest *
+ccnxManifest_CreateNameless(void)
+{
+ return _ccnxManifest_InternalCreate(_defaultImplementation, NULL);
+}
+
+void
+ccnxManifest_AddHashGroup(CCNxManifest *manifest, const CCNxManifestHashGroup *group)
+{
+ CCNxManifestInterface *interface = ccnxManifestInterface_GetInterface(manifest);
+ interface->addHashGroup(manifest, group);
+}
+
+CCNxManifestHashGroup *
+ccnxManifest_GetHashGroupByIndex(const CCNxManifest *manifest, size_t index)
+{
+ CCNxManifestInterface *interface = ccnxManifestInterface_GetInterface(manifest);
+ return interface->getHashGroup(manifest, index);
+}
+
+size_t
+ccnxManifest_GetNumberOfHashGroups(const CCNxManifest *manifest)
+{
+ CCNxManifestInterface *impl = ccnxManifestInterface_GetInterface(manifest);
+ size_t result = 0;
+ if (impl->getNumberOfHashGroups != NULL) {
+ result = (impl->getNumberOfHashGroups)(manifest);
+ }
+ return result;
+}
+
+const CCNxName *
+ccnxManifest_GetName(const CCNxManifest *manifest)
+{
+ CCNxManifestInterface *impl = ccnxManifestInterface_GetInterface(manifest);
+
+ const CCNxName *result = NULL;
+
+ if (impl->getName != NULL) {
+ result = impl->getName(manifest);
+ } else {
+ trapNotImplemented("ccnxManifest_GetName");
+ }
+
+ return result;
+}
+
+bool
+ccnxManifest_Equals(const CCNxManifest *objectA, const CCNxManifest *objectB)
+{
+ if (objectA == objectB) {
+ return true;
+ }
+ if (objectA == NULL || objectB == NULL) {
+ return false;
+ }
+
+ CCNxManifestInterface *impl = ccnxManifestInterface_GetInterface(objectA);
+ return (impl->equals)(objectA, objectB);
+
+ return false;
+}
+
+PARCJSON *
+ccnxManifest_ToJSON(const CCNxManifest *manifest)
+{
+ PARCJSON *root = parcJSON_Create();
+
+ char *nameString = ccnxName_ToString(ccnxManifest_GetName(manifest));
+ parcJSON_AddString(root, "locator", nameString);
+ parcMemory_Deallocate(&nameString);
+
+ PARCJSONArray *array = parcJSONArray_Create();
+ for (size_t i = 0; i < ccnxManifest_GetNumberOfHashGroups(manifest); i++) {
+ CCNxManifestHashGroup *group = ccnxManifest_GetHashGroupByIndex(manifest, i);
+ PARCJSON *groupJson = ccnxManifestHashGroup_ToJson(group);
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromJSON(groupJson);
+
+ parcJSONArray_AddValue(array, jsonValue);
+
+ parcJSONValue_Release(&jsonValue);
+ parcJSON_Release(&groupJson);
+ ccnxManifestHashGroup_Release(&group);
+ }
+ parcJSON_AddArray(root, "HashGroups", array);
+ parcJSONArray_Release(&array);
+
+ return root;
+}
+
+char *
+ccnxManifest_ToString(const CCNxManifest *manifest)
+{
+ PARCJSON *json = ccnxManifest_ToJSON(manifest);
+ char *string = parcJSON_ToString(json);
+ parcJSON_Release(&json);
+ return string;
+}
+
+void
+ccnxManifest_AssertValid(const CCNxManifest *manifest)
+{
+ assertNotNull(manifest, "Non-NULL manifest");
+}
+
+PARCLinkedList *
+ccnxManifest_CreateInterestList(const CCNxManifest *manifest, const CCNxName *locator)
+{
+ PARCLinkedList *interests = parcLinkedList_Create();
+
+ for (size_t i = 0; i < ccnxManifest_GetNumberOfHashGroups(manifest); i++) {
+ CCNxManifestHashGroup *group = ccnxManifest_GetHashGroupByIndex(manifest, i);
+
+ const CCNxName *name = ccnxManifest_GetName(manifest) == NULL ? locator : ccnxManifest_GetName(manifest);
+ PARCLinkedList *groupInterests = ccnxManifestHashGroup_CreateInterestList(group, name);
+ parcLinkedList_AppendAll(interests, groupInterests);
+ parcLinkedList_Release(&groupInterests);
+
+ ccnxManifestHashGroup_Release(&group);
+ }
+
+ return interests;
+}
diff --git a/libccnx-common/ccnx/common/ccnx_Manifest.h b/libccnx-common/ccnx/common/ccnx_Manifest.h
new file mode 100755
index 00000000..4e3b1076
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_Manifest.h
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_Manifest.h
+ * @ingroup ContentObject
+ * @brief The generic manifest.
+ *
+ */
+#ifndef libccnx_ccnx_Manifest_h
+#define libccnx_ccnx_Manifest_h
+
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/common/ccnx_ManifestHashGroup.h>
+
+#include <ccnx/common/internal/ccnx_ManifestInterface.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+#include <parc/security/parc_Signature.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_LinkedList.h>
+#include <parc/algol/parc_Buffer.h>
+
+struct ccnx_manifest;
+
+/**
+ * @typedef CCNxManifest
+ * @brief Structure of the CCNxManifest
+ */
+typedef CCNxTlvDictionary CCNxManifest;
+
+/**
+ * Create a new `CCNxManifest` instance.
+ *
+ * @param [in] nameLink A pointer to a `CCNxName`
+ * @param [in] payload A pointer to a `CCNxManifestSection`
+ *
+ * @return A pointer to a `CCNxManifest` instance, or NULL if an error or out of memory.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromURI("lci:/foo/bar/manifest");
+ *
+ *
+ * CCNxManifest *object = ccnxManifest_Create(name, payload);
+ * }
+ * @endcode
+ */
+CCNxManifest *ccnxManifest_Create(const CCNxName *name);
+
+/**
+ * Create a new nameless `CCNxManifest` instance.
+ *
+ * @return A pointer to a `CCNxManifest` instance, or NULL if an error or out of memory.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifest *object = ccnxManifest_CreateNameless();
+ * }
+ * @endcode
+ */
+CCNxManifest *ccnxManifest_CreateNameless(void);
+
+/**
+ * Increase the number of references to an instance of this object.
+ *
+ * Note that new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the reference by invoking {@link ccnxManifest_Release()}.
+ *
+ * @param [in] manifest A pointer to the instance of `CCNxManifest` to acquire.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifest *manifest = ccnxManifest_Acquire(instance);
+ *
+ * ccnxManifest_Release(&manifest);
+ * }
+ * @endcode
+ *
+ * @see `ccnxManifest_Release`
+ */
+CCNxManifest *ccnxManifest_Acquire(const CCNxManifest *manifest);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] manifestP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifest *manifest = ccnxManifest_Acquire(instance);
+ *
+ * ccnxManifest_Release(&manifest);
+ *
+ * }
+ * @endcode
+ */
+void ccnxManifest_Release(CCNxManifest **manifestP);
+
+/**
+ * Check that the pointer to the `CCNxManifest` is valid. It should be non-null,
+ * and any referenced data should also be valid.
+ *
+ * @param [in] manifest A pointer to an instance of `CCNxManifest` to check.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifest *manifest = ccnxManifest_Acquire(instance);
+ *
+ * ccnxManifest_AssertValid(manifest);
+ *
+ * }
+ * @endcode
+ */
+void ccnxManifest_AssertValid(const CCNxManifest *manifest);
+
+/**
+ * Add a HashGroup to the given `CCNxManifest`.
+ *
+ * @param [in] manifest A pointer to an instance of `CCNxManifest`.
+ * @param [in] group A pointer to an instance of `CCNxManifestHashGroup`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifest *manifest = ...
+ * CCNxManifestHashGroup *group = ...;
+ *
+ * ccnxManifest_AddHashGroup(manifest, group);
+ * }
+ * @endcode
+ */
+void ccnxManifest_AddHashGroup(CCNxManifest *manifest, const CCNxManifestHashGroup *group);
+
+/**
+ * Get the `CCNxManifestHashGroup` corresponding to the specified index.
+ *
+ * @param [in] manifest A pointer to an instance of `CCNxManifest`.
+ * @param [in] index The index of the `CCNxManifestHashGroup` to retrieve.
+ *
+ * @return A pointer to a `CCNxManifestHashGroup`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifest *manifest = ...
+ * CCNxManifestHashGroup *group = ...;
+ *
+ * // Add the first group
+ * ccnxManifest_AddHashGroup(manifest, group);
+ *
+ * CCNxManifestHashGroup *expected = ccnxManifest_GetHashGroup(manifest, 0);
+ * }
+ * @endcode
+ */
+CCNxManifestHashGroup *ccnxManifest_GetHashGroupByIndex(const CCNxManifest *manifest, size_t index);
+
+/**
+ * Get the number of {@link CCNxManifestHashGroup} instances in the specified manifest.
+ *
+ * @param [in] manifest A pointer to an instance of {@link CCNxManifest}.
+ *
+ * @return A pointer to a {@link CCNxManifestHashGroup}.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifest *manifest = ...
+ * CCNxManifestHashGroup *group = ...;
+ *
+ * // Add the first group
+ * ccnxManifest_AddHashGroup(manifest, group);
+ *
+ * // Add more groups...
+ *
+ * printf("Number of hash groups: %d\n", ccnxManifest_GetNumberOfHashGroups(manifest));
+ * }
+ * @endcode
+ */
+size_t ccnxManifest_GetNumberOfHashGroups(const CCNxManifest *manifest);
+
+/**
+ * Create a list of `CCNxInterest` instances that can be created from this single
+ * `CCNxManifest` instance.
+ *
+ * @param [in] manifest A pointer to an instance of `CCNxManifest`.
+ * @param [in] name A `CCNxName` locator for the interests in this list.
+ *
+ * @return A `PARCLinkedList` containing the set of all Interests that can be
+ * constructed from this Manifest
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifest *manifest = ...;
+ * CCNxName *locator = ...;
+ *
+ * PARCLinkedList *interests = ccnxManifest_CreateInterestList(manifest, locator);
+ * }
+ * @endcode
+ */
+PARCLinkedList *ccnxManifest_CreateInterestList(const CCNxManifest *manifest, const CCNxName *name);
+
+/**
+ * Get the `CCNxName` for the given `CCNxManifest`.
+ *
+ * @param [in] manifest A pointer to an instance of `CCNxManifest`.
+ * @return A pointer to the `CCNxName`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifest *manifest = ...;
+ *
+ * CCNxName *name = ccnxManifest_GetName(manifest);
+ * }
+ * @endcode
+ */
+const CCNxName *ccnxManifest_GetName(const CCNxManifest *manifest);
+
+/**
+ * Determine if two `CCNxManifest` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxManifest` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `ccnxManifest_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxManifest_Equals(x, y)` must return true if and only if
+ * `ccnxManifest_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxManifest_Equals(x, y)` returns true and
+ * `ccnxManifest_Equals(y, z)` returns true,
+ * then `ccnxManifest_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxManifest_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxManifest_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] x A pointer to a `CCNxManifest` instance.
+ * @param [in] y A pointer to a `CCNxManifest` instance.
+ * @return `true` if the referenced `CCNxManifest` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifest *a = CCNxManifest_Create(...);
+ * CCNxManifest *b = CCNxManifest_Create(...);
+ *
+ * if (CCNxManifest_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool ccnxManifest_Equals(const CCNxManifest *x, const CCNxManifest *y);
+
+/**
+ * Create a null-terminated string representation of the given {@link CCNxManifest}.
+ *
+ * The returned value must be freed by the caller using {@link parcMemory_Deallocate()}.
+ *
+ * @param [in] manifest A pointer to an instance of {@link CCNxManifest}.
+ * @return A pointer to null-terminated string of characters that must be freed by the caller by `parcMemory_Deallocate()`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifest *manifest = ...;
+ *
+ * char *stringForm = ccnxManifest_ToString(manifest);
+ * }
+ * @endcode
+ */
+char *ccnxManifest_ToString(const CCNxManifest *manifest);
+#endif // libccnx_ccnx_Manifest_h
diff --git a/libccnx-common/ccnx/common/ccnx_ManifestHashGroup.c b/libccnx-common/ccnx/common/ccnx_ManifestHashGroup.c
new file mode 100644
index 00000000..cfe37742
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_ManifestHashGroup.c
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_LinkedList.h>
+
+#include <ccnx/common/ccnx_Interest.h>
+#include <ccnx/common/ccnx_ManifestHashGroup.h>
+#include <ccnx/common/internal/ccnx_WireFormatMessageInterface.h>
+
+#define MAX_NUMBER_OF_POINTERS 1500 // loose upper bound imposed by packet format
+
+struct ccnx_manifest_hash_group {
+ PARCLinkedList *pointers;
+
+ // Metadata
+ const PARCBuffer *overallDataDigest; // overall *application data* digest
+ size_t dataSize; // size for all pointers (last pointer might not be entrySize unless perfectly balanced)
+ size_t entrySize; // size per pointer
+ size_t blockSize; // size of nodes used in the tree (e.g., 4K for each Manifest or Data node)
+ size_t treeHeight; // height of sub-tree referred to by each pointer
+ const CCNxName *locator; // locator for the hash group
+};
+
+struct ccnx_manifest_hash_group_pointer {
+ CCNxManifestHashGroupPointerType pointerType;
+ PARCBuffer *digest;
+};
+
+static bool
+CCNxManifestHashGroupPointer_FinalRelease(CCNxManifestHashGroupPointer **ptrP)
+{
+ if ((*ptrP)->digest != NULL) {
+ parcBuffer_Release(&(*ptrP)->digest);
+ }
+ return true;
+}
+
+static bool
+_CCNxManifestHashGroupPointer_Equals(const CCNxManifestHashGroupPointer *objectA, const CCNxManifestHashGroupPointer *objectB)
+{
+ if (objectA == objectB) {
+ return true;
+ }
+ if (objectA == NULL || objectB == NULL) {
+ return false;
+ }
+ if (objectA->pointerType == objectB->pointerType) {
+ if (parcBuffer_Equals(objectA->digest, objectB->digest)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+parcObject_Override(CCNxManifestHashGroupPointer, PARCObject,
+ .destructor = (PARCObjectDestructor *) CCNxManifestHashGroupPointer_FinalRelease,
+ .equals = (PARCObjectEquals *) _CCNxManifestHashGroupPointer_Equals);
+
+parcObject_ImplementAcquire(ccnxManifestHashGroupPointer, CCNxManifestHashGroupPointer);
+parcObject_ImplementRelease(ccnxManifestHashGroupPointer, CCNxManifestHashGroupPointer);
+
+CCNxManifestHashGroupPointer *
+ccnxManifestHashGroupPointer_Create(CCNxManifestHashGroupPointerType type, const PARCBuffer *digest)
+{
+ CCNxManifestHashGroupPointer *ptr = parcObject_CreateAndClearInstance(CCNxManifestHashGroupPointer);
+ if (ptr != NULL) {
+ ptr->pointerType = type;
+ ptr->digest = parcBuffer_Acquire(digest);
+ }
+ return ptr;
+}
+
+CCNxManifestHashGroupPointerType
+ccnxManifestHashGroupPointer_GetType(const CCNxManifestHashGroupPointer *ptr)
+{
+ return ptr->pointerType;
+}
+
+const PARCBuffer *
+ccnxManifestHashGroupPointer_GetDigest(const CCNxManifestHashGroupPointer *ptr)
+{
+ return ptr->digest;
+}
+
+static bool
+_ccnxManifestHashGroup_Destructor(CCNxManifestHashGroup **groupP)
+{
+ if ((*groupP)->pointers != NULL) {
+ parcLinkedList_Release(&(*groupP)->pointers);
+ }
+ if ((*groupP)->overallDataDigest != NULL) {
+ parcBuffer_Release((PARCBuffer **) &(*groupP)->overallDataDigest);
+ }
+ if ((*groupP)->locator != NULL) {
+ ccnxName_Release((CCNxName **) &(*groupP)->locator);
+ }
+ return true;
+}
+
+parcObject_Override(CCNxManifestHashGroup, PARCObject,
+ .destructor = (PARCObjectDestructor *) _ccnxManifestHashGroup_Destructor,
+ .toString = (PARCObjectToString *) ccnxManifestHashGroup_ToString,
+ .equals = (PARCObjectEquals *) ccnxManifestHashGroup_Equals);
+
+parcObject_ImplementAcquire(ccnxManifestHashGroup, CCNxManifestHashGroup);
+parcObject_ImplementRelease(ccnxManifestHashGroup, CCNxManifestHashGroup);
+
+CCNxManifestHashGroup *
+ccnxManifestHashGroup_Create(void)
+{
+ CCNxManifestHashGroup *section = parcObject_CreateAndClearInstance(CCNxManifestHashGroup);
+
+ if (section != NULL) {
+ section->pointers = parcLinkedList_Create();
+
+ section->overallDataDigest = NULL;
+ section->dataSize = 0;
+ section->entrySize = 0;
+ section->blockSize = 0;
+ section->treeHeight = 0;
+ section->locator = NULL;
+ }
+
+ return section;
+}
+
+bool
+ccnxManifestHashGroup_AppendPointer(CCNxManifestHashGroup *group, CCNxManifestHashGroupPointerType type, const PARCBuffer *buffer)
+{
+ if (!ccnxManifestHashGroup_IsFull(group)) {
+ CCNxManifestHashGroupPointer *ptr = ccnxManifestHashGroupPointer_Create(type, buffer);
+ parcLinkedList_Append(group->pointers, ptr);
+ ccnxManifestHashGroupPointer_Release(&ptr);
+ return true;
+ }
+ return false;
+}
+
+bool
+ccnxManifestHashGroup_PrependPointer(CCNxManifestHashGroup *group, CCNxManifestHashGroupPointerType type, const PARCBuffer *buffer)
+{
+ if (!ccnxManifestHashGroup_IsFull(group)) {
+ CCNxManifestHashGroupPointer *ptr = ccnxManifestHashGroupPointer_Create(type, buffer);
+ parcLinkedList_Prepend(group->pointers, ptr);
+ ccnxManifestHashGroupPointer_Release(&ptr);
+ return true;
+ }
+ return false;
+}
+
+void
+ccnxManifestHashGroup_SetOverallDataDigest(CCNxManifestHashGroup *group, const PARCBuffer *digest)
+{
+ group->overallDataDigest = parcBuffer_Acquire(digest);
+}
+
+const PARCBuffer *
+ccnxManifestHashGroup_GetOverallDataDigest(const CCNxManifestHashGroup *group)
+{
+ return group->overallDataDigest;
+}
+
+size_t
+ccnxManifestHashGroup_GetTotalSize(const CCNxManifestHashGroup *group)
+{
+ return group->dataSize;
+}
+
+size_t
+ccnxManifestHashGroup_GetChildBlockSize(const CCNxManifestHashGroup *group)
+{
+ return group->entrySize;
+}
+
+void
+ccnxManifestHashGroup_SetLocator(CCNxManifestHashGroup *group, const CCNxName *locator)
+{
+ group->locator = ccnxName_Acquire(locator);
+}
+
+const CCNxName *
+ccnxManifestHashGroup_GetLocator(const CCNxManifestHashGroup *group)
+{
+ return group->locator;
+}
+
+size_t
+ccnxManifestHashGroup_GetNumberOfPointers(const CCNxManifestHashGroup *group)
+{
+ return parcLinkedList_Size(group->pointers);
+}
+
+CCNxManifestHashGroupPointer *
+ccnxManifestHashGroup_GetPointerAtIndex(const CCNxManifestHashGroup *group, size_t index)
+{
+ CCNxManifestHashGroupPointer *entry = parcLinkedList_GetAtIndex(group->pointers, index);
+ return entry;
+}
+
+CCNxManifestHashGroupPointerType
+ccnxManifestHashGroup_GetPointerTypeAtIndex(const CCNxManifestHashGroup *group, size_t index)
+{
+ CCNxManifestHashGroupPointer *entry = parcLinkedList_GetAtIndex(group->pointers, index);
+ return entry->pointerType;
+}
+
+PARCBuffer *
+ccnxManifestHashGroup_GetPointerDigestAtIndex(const CCNxManifestHashGroup *group, size_t index)
+{
+ CCNxManifestHashGroupPointer *entry = parcLinkedList_GetAtIndex(group->pointers, index);
+ return entry->digest;
+}
+
+bool
+ccnxManifestHashGroup_IsFull(const CCNxManifestHashGroup *group)
+{
+ size_t size = parcLinkedList_Size(group->pointers);
+ return size >= MAX_NUMBER_OF_POINTERS;
+}
+
+bool
+ccnxManifestHashGroup_Equals(const CCNxManifestHashGroup *objectA, const CCNxManifestHashGroup *objectB)
+{
+ if (objectA == objectB) {
+ return true;
+ }
+ if (objectA == NULL || objectB == NULL) {
+ return false;
+ }
+
+ if (objectA->dataSize == objectB->dataSize) {
+ if (objectA->entrySize == objectB->entrySize) {
+ if (objectA->blockSize == objectB->blockSize) {
+ if (objectA->treeHeight == objectB->treeHeight) {
+ if (ccnxName_Equals(objectA->locator, objectB->locator)) {
+ if (parcBuffer_Equals(objectA->overallDataDigest, objectB->overallDataDigest)) {
+ if (parcLinkedList_Size(objectA->pointers) == parcLinkedList_Size(objectB->pointers)) {
+ for (size_t i = 0; i < parcLinkedList_Size(objectA->pointers); i++) {
+ CCNxManifestHashGroupPointer *ptrA = parcLinkedList_GetAtIndex(objectA->pointers, i);
+ CCNxManifestHashGroupPointer *ptrB = parcLinkedList_GetAtIndex(objectB->pointers, i);
+ if (!_CCNxManifestHashGroupPointer_Equals(ptrA, ptrB)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+char *
+ccnxManifestHashGroup_ToString(const CCNxManifestHashGroup *section)
+{
+ PARCJSON *json = ccnxManifestHashGroup_ToJson(section);
+ char *stringRep = parcJSON_ToString(json);
+ parcJSON_Release(&json);
+ return stringRep;
+}
+
+PARCJSON *
+ccnxManifestHashGroup_ToJson(const CCNxManifestHashGroup *group)
+{
+ PARCJSON *root = parcJSON_Create();
+
+ PARCJSONArray *ptrList = parcJSONArray_Create();
+ for (size_t i = 0; i < parcLinkedList_Size(group->pointers); i++) {
+ CCNxManifestHashGroupPointer *ptr = (CCNxManifestHashGroupPointer *) parcLinkedList_GetAtIndex(group->pointers, i);
+ PARCJSON *ptrJson = parcJSON_Create();
+
+ // Type.
+ parcJSON_AddInteger(ptrJson, "type", ccnxManifestHashGroupPointer_GetType(ptr));
+
+ // Digest.
+ char *digestString = parcBuffer_ToHexString(ptr->digest);
+ parcJSON_AddString(ptrJson, "digest", digestString);
+ parcMemory_Deallocate(&digestString);
+
+ // Add the tuple to the list.
+ PARCJSONValue *val = parcJSONValue_CreateFromJSON(ptrJson);
+ parcJSONArray_AddValue(ptrList, val);
+
+ // Cleanup
+ parcJSONValue_Release(&val);
+ parcJSON_Release(&ptrJson);
+ }
+ root = parcJSON_AddArray(root, "HashGroup", ptrList);
+ parcJSONArray_Release(&ptrList);
+
+ if (group->overallDataDigest != NULL) {
+ char *digestString = parcBuffer_ToHexString(group->overallDataDigest);
+ root = parcJSON_AddString(root, "overallDataDigest", digestString);
+ parcMemory_Deallocate((void **) &digestString);
+ }
+
+ if (group->locator != NULL) {
+ char *locatorString = ccnxName_ToString(group->locator);
+ root = parcJSON_AddString(root, "locator", locatorString);
+ parcMemory_Deallocate((void **) &locatorString);
+ }
+
+ if (group->entrySize > 0) {
+ root = parcJSON_AddInteger(root, "entrySize", group->entrySize);
+ }
+
+ if (group->dataSize > 0) {
+ root = parcJSON_AddInteger(root, "dataSize", group->dataSize);
+ }
+
+ if (group->blockSize > 0) {
+ root = parcJSON_AddInteger(root, "blockSize", group->blockSize);
+ }
+
+ if (group->treeHeight > 0) {
+ root = parcJSON_AddInteger(root, "treeHeight", group->treeHeight);
+ }
+
+ return root;
+}
+
+CCNxManifestHashGroup *
+ccnxManifestHashGroup_CreateFromJson(const PARCJSON *json)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+
+ PARCJSONValue *ptrListValue = parcJSON_GetValueByName(json, "HashGroup");
+ PARCJSONArray *ptrList = parcJSONValue_GetArray(ptrListValue);
+ size_t numberOfPointers = parcJSONArray_GetLength(ptrList);
+ for (size_t i = 0; i < numberOfPointers; i++) {
+ PARCJSONValue *pointerValue = parcJSONArray_GetValue(ptrList, i);
+
+ PARCJSON *typeJson = parcJSONValue_GetJSON(pointerValue);
+ PARCJSONValue *typeValue = parcJSON_GetValueByName(typeJson, "type");
+ CCNxManifestHashGroupPointerType type;
+
+ if (parcJSONValue_GetInteger(typeValue) == 0) {
+ type = CCNxManifestHashGroupPointerType_Data;
+ } else {
+ type = CCNxManifestHashGroupPointerType_Manifest;
+ }
+
+ PARCJSON *digestJson = parcJSONValue_GetJSON(pointerValue);
+ PARCJSONValue *digestValue = parcJSON_GetValueByName(digestJson, "digest");
+ PARCBuffer *digestHex = parcJSONValue_GetString(digestValue);
+
+ char *hexString = parcBuffer_ToString(digestHex);
+ PARCBuffer *digest = parcBuffer_Flip(parcBuffer_ParseHexString(hexString));
+ parcMemory_Deallocate(&hexString);
+
+ ccnxManifestHashGroup_AppendPointer(group, type, digest);
+ parcBuffer_Release(&digest);
+ }
+
+ if (parcJSON_GetPairByName(json, "overallDataDigest") != NULL) {
+ PARCJSONValue *overallDataDigestValue = parcJSON_GetValueByName(json, "overallDataDigest");
+ PARCBuffer *digestHex = parcJSONValue_GetString(overallDataDigestValue);
+
+ char *hexString = parcBuffer_ToString(digestHex);
+ group->overallDataDigest = parcBuffer_Flip(parcBuffer_ParseHexString(hexString));
+ parcMemory_Deallocate(&hexString);
+ }
+
+ if (parcJSON_GetPairByName(json, "locator") != NULL) {
+ PARCJSONValue *locatorValue = parcJSON_GetValueByName(json, "locator");
+ PARCBuffer *buffer = parcJSONValue_GetString(locatorValue);
+ char *locator = parcBuffer_ToString(buffer);
+ group->locator = ccnxName_CreateFromCString(locator);
+ parcMemory_Deallocate(&locator);
+ }
+
+ if (parcJSON_GetPairByName(json, "entrySize") != NULL) {
+ PARCJSONValue *childBlockNodeSizeValue = parcJSON_GetValueByName(json, "entrySize");
+ group->entrySize = parcJSONValue_GetInteger(childBlockNodeSizeValue);
+ }
+
+ if (parcJSON_GetPairByName(json, "dataSize") != NULL) {
+ PARCJSONValue *totalSizeValue = parcJSON_GetValueByName(json, "dataSize");
+ group->dataSize = parcJSONValue_GetInteger(totalSizeValue);
+ }
+
+ if (parcJSON_GetPairByName(json, "blockSize") != NULL) {
+ PARCJSONValue *blockSizeValue = parcJSON_GetValueByName(json, "blockSize");
+ group->blockSize = parcJSONValue_GetInteger(blockSizeValue);
+ }
+
+ if (parcJSON_GetPairByName(json, "treeHeight") != NULL) {
+ PARCJSONValue *treeHeightValue = parcJSON_GetValueByName(json, "treeHeight");
+ group->treeHeight = parcJSONValue_GetInteger(treeHeightValue);
+ }
+
+ return group;
+}
+
+struct _hashgroup_ccnxManifestHashGroupIterator_state {
+ size_t pointerNumber;
+ bool atEnd;
+};
+typedef struct _hashgroup_ccnxManifestHashGroupIterator_state _HashgroupIteratorState;
+
+static void *
+_ccnxManifestHashGroupIterator_Init(CCNxManifestHashGroup *group)
+{
+ _HashgroupIteratorState *state = parcMemory_Allocate(sizeof(_HashgroupIteratorState));
+ state->pointerNumber = 0;
+ state->atEnd = false;
+ return state;
+}
+
+static bool
+_ccnxManifestHashGroupIterator_HasNext(CCNxManifestHashGroup *group, void *voidstate)
+{
+ _HashgroupIteratorState *state = (_HashgroupIteratorState *) voidstate;
+ return !state->atEnd;
+}
+
+static void *
+_ccnxManifestHashGroupIterator_Next(CCNxManifestHashGroup *group, void *state)
+{
+ _HashgroupIteratorState *thestate = (_HashgroupIteratorState *) state;
+ thestate->pointerNumber++;
+
+ if (thestate->pointerNumber == parcLinkedList_Size(group->pointers)) {
+ thestate->atEnd = true;
+ }
+
+ return thestate;
+}
+
+static void
+_ccnxManifestHashGroupIterator_RemoveAt(CCNxManifestHashGroup *group, void **state)
+{
+ // pass
+}
+
+static void *
+_ccnxManifestHashGroupIterator_GetElement(CCNxManifestHashGroup *group, void *state)
+{
+ _HashgroupIteratorState *thestate = (_HashgroupIteratorState *) state;
+ CCNxManifestHashGroupPointer *ptr =
+ (CCNxManifestHashGroupPointer *) parcLinkedList_GetAtIndex(group->pointers, thestate->pointerNumber - 1);
+ return ptr;
+}
+
+static void
+_ccnxManifestHashGroupIterator_Finish(CCNxManifestHashGroup *group, void *state)
+{
+ _HashgroupIteratorState *thestate = (_HashgroupIteratorState *) state;
+ parcMemory_Deallocate(&thestate);
+}
+
+static void
+_ccnxManifestHashGroupIterator_AssertValid(const void *state)
+{
+ // pass
+}
+
+PARCIterator *
+ccnxManifestHashGroup_Iterator(const CCNxManifestHashGroup *group)
+{
+ PARCIterator *iterator = parcIterator_Create((void *) group,
+ (void *(*)(PARCObject *))_ccnxManifestHashGroupIterator_Init,
+ (bool (*)(PARCObject *, void *))_ccnxManifestHashGroupIterator_HasNext,
+ (void *(*)(PARCObject *, void *))_ccnxManifestHashGroupIterator_Next,
+ (void (*)(PARCObject *, void **))_ccnxManifestHashGroupIterator_RemoveAt,
+ (void *(*)(PARCObject *, void *))_ccnxManifestHashGroupIterator_GetElement,
+ (void (*)(PARCObject *, void *))_ccnxManifestHashGroupIterator_Finish,
+ (void (*)(const void *))_ccnxManifestHashGroupIterator_AssertValid);
+
+ return iterator;
+}
+
+size_t
+ccnxManifestHashGroup_GetBlockSize(const CCNxManifestHashGroup *group)
+{
+ return group->blockSize;
+}
+
+void
+ccnxManifestHashGroup_SetBlockSize(CCNxManifestHashGroup *group, size_t blockSize)
+{
+ group->blockSize = blockSize;
+}
+
+size_t
+ccnxManifestHashGroup_GetDataSize(const CCNxManifestHashGroup *group)
+{
+ return group->dataSize;
+}
+
+void
+ccnxManifestHashGroup_SetDataSize(CCNxManifestHashGroup *group, size_t dataSize)
+{
+ group->dataSize = dataSize;
+}
+
+size_t
+ccnxManifestHashGroup_GetEntrySize(const CCNxManifestHashGroup *group)
+{
+ return group->entrySize;
+}
+
+void
+ccnxManifestHashGroup_SetEntrySize(CCNxManifestHashGroup *group, size_t entrySize)
+{
+ group->entrySize = entrySize;
+}
+
+size_t
+ccnxManifestHashGroup_GetTreeHeight(const CCNxManifestHashGroup *group)
+{
+ return group->treeHeight;
+}
+
+void
+ccnxManifestHashGroup_SetTreeHeight(CCNxManifestHashGroup *group, size_t treeHeight)
+{
+ group->treeHeight = treeHeight;
+}
+
+bool
+ccnxManifestHashGroup_HasMetadata(const CCNxManifestHashGroup *group)
+{
+ // Check the existence of each metadata value.
+ if (group->blockSize > 0) {
+ return true;
+ }
+ if (group->dataSize > 0) {
+ return true;
+ }
+ if (group->entrySize > 0) {
+ return true;
+ }
+ if (group->locator != NULL) {
+ return true;
+ }
+ if (group->overallDataDigest != NULL) {
+ return true;
+ }
+
+ return false;
+}
+
+PARCLinkedList *
+ccnxManifestHashGroup_CreateInterestList(const CCNxManifestHashGroup *group, const CCNxName *locator)
+{
+ PARCLinkedList *interestList = parcLinkedList_Create();
+
+ PARCIterator *itr = ccnxManifestHashGroup_Iterator(group);
+ while (parcIterator_HasNext(itr)) {
+ // Extract the name and digest
+ CCNxManifestHashGroupPointer *ptr = parcIterator_Next(itr);
+ const PARCBuffer *digest = ccnxManifestHashGroupPointer_GetDigest(ptr);
+ const CCNxName *name = group->locator == NULL ? locator : group->locator;
+
+ // Build the interest and append it to the running list
+ if (name != NULL) {
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxInterest_SetContentObjectHashRestriction(interest, digest);
+ parcLinkedList_Append(interestList, interest);
+ ccnxInterest_Release(&interest);
+ }
+ }
+ parcIterator_Release(&itr);
+
+ return interestList;
+}
diff --git a/libccnx-common/ccnx/common/ccnx_ManifestHashGroup.h b/libccnx-common/ccnx/common/ccnx_ManifestHashGroup.h
new file mode 100755
index 00000000..092434b1
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_ManifestHashGroup.h
@@ -0,0 +1,692 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_ManifestHashGroup.h
+ * @brief A HashGroup in a FLIC manifest.
+ *
+ */
+#ifndef libccnx_ccnx_ManifestHashGroup_h
+#define libccnx_ccnx_ManifestHashGroup_h
+
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_Iterator.h>
+#include <parc/algol/parc_LinkedList.h>
+
+#include <parc/security/parc_Signature.h>
+
+struct ccnx_manifest_hash_group;
+/**
+ * @typedef CCNxManifestHashGroup
+ * @brief A FLIC HashGroup
+ */
+typedef struct ccnx_manifest_hash_group CCNxManifestHashGroup;
+
+typedef enum {
+ CCNxManifestHashGroupPointerType_Data,
+ CCNxManifestHashGroupPointerType_Manifest
+} CCNxManifestHashGroupPointerType;
+
+/**
+ * @typedef CCNxManifestHashGroupPointer
+ * @brief A HashGroup pointer.
+ */
+struct ccnx_manifest_hash_group_pointer;
+typedef struct ccnx_manifest_hash_group_pointer CCNxManifestHashGroupPointer;
+
+/**
+ * Retrieve the type of a `CCNxManifestHashGroupPointer`.
+ *
+ * @param [in] ptr A `CCNxManifestHashGroupPointer` instance.
+ *
+ * @retval The type of the `CCNxManifestHashGroupPointer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroupPointer *pointer = ccnxManifestHashGroup_GetPointerAtIndex(group, 0);
+ * CCNxManifestHashGroupPointerType type = ccnxManifestHashGroupPointer_GetType(pointer);
+ * if (type == CCNxManifestHashGroupPointerType_Data) {
+ * // Data
+ * } else {
+ * // Manifest
+ * }
+ * }
+ * @endcode
+ */
+CCNxManifestHashGroupPointerType ccnxManifestHashGroupPointer_GetType(const CCNxManifestHashGroupPointer *ptr);
+
+/**
+ * Retrieve hash digest associated with the `CCNxManifestHashGroupPointer` value.
+ *
+ * @param [in] ptr A `CCNxManifestHashGroupPointer` instance.
+ *
+ * @retval The hash digest for a `CCNxManifestHashGroupPointer` in a `PARCBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroupPointer *pointer = ccnxManifestHashGroup_GetPointerAtIndex(group, 0);
+ * PARCBuffer *digest = ccnxManifestHashGroupPointer_GetDigest(pointer);
+ * // use the digest
+ * }
+ * @endcode
+ */
+const PARCBuffer *ccnxManifestHashGroupPointer_GetDigest(const CCNxManifestHashGroupPointer *ptr);
+
+/**
+ * Create a new and empty {@link CCNxManifestHashGroup} instance.
+ *
+ * @return A pointer to a {@link CCNxManifestHashGroup} instance, or NULL if an error or out of memory.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *section = CCNxManifestHashGroup_Create();
+ *
+ * ...
+ *
+ * CCNxManifestHashGroup_Release(&section);
+ * }
+ * @endcode
+ */
+CCNxManifestHashGroup *ccnxManifestHashGroup_Create();
+
+/**
+ * Create a new {@link CCNxManifestHashGroup} instance from a
+ *
+ * @param [in] jsonRepresentation - A pointer to a {@link PARCJSON} object representing the `CCNxManifestHashGroup`.
+ *
+ * @return A pointer to a {@link CCNxManifestHashGroup} instance, or NULL if an error or out of memory.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *jsonRep = ccnxTlvDictionary_GetJson(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ManifestHashGroup);
+ * CCNxManifestHashGroup *section = CCNxManifestHashGroup_CreateFromJson(jsonRep);
+ *
+ * ...
+ *
+ * ccnxJson_Destroy(&jsonRep);
+ * CCNxManifestHashGroup_Release(&section);
+ * }
+ * @endcode
+ */
+CCNxManifestHashGroup *ccnxManifestHashGroup_CreateFromJson(const PARCJSON *jsonRepresentation);
+
+/**
+ * Increase the number of references to an instance of this object.
+ *
+ * Note that new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the reference by invoking {@link CCNxManifestHashGroup_Release()}.
+ *
+ * @param [in] group A pointer to the {@link CCNxManifestHashGroup} to acquire.
+ * @return The value of the input parameter @p group.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifest *manifest = CCNxManifestHashGroup_Acquire(instance);
+ *
+ * CCNxManifestHashGroup_Release(&manifest);
+ * }
+ * @endcode
+ *
+ * @see `CCNxManifestHashGroup_Release`
+ */
+CCNxManifestHashGroup *ccnxManifestHashGroup_Acquire(const CCNxManifestHashGroup *group);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] sectionP A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *manifest = CCNxManifestHashGroup_Acquire(instance);
+ *
+ * CCNxManifestHashGroup_Release(&manifest);
+ * }
+ * @endcode
+ */
+void ccnxManifestHashGroup_Release(CCNxManifestHashGroup **sectionP);
+
+/**
+ * Check that the pointer to the {@link CCNxManifestHashGroup} is valid. It should be non-null,
+ * and any referenced data should also be valid.
+ *
+ * @param [in] manifest A pointer to the {@link CCNxManifestHashGroup} to check.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifest *manifest = CCNxManifestHashGroup_Acquire(instance);
+ *
+ * CCNxManifestHashGroup_AssertValid(manifest);
+ * }
+ * @endcode
+ */
+void ccnxManifestHashGroup_AssertValid(const CCNxManifestHashGroup *manifest);
+
+/**
+ * Add a new pointer to the {@link CCNxManifestHashGroup} with the specified type and hash digest.
+ *
+ * @param [in] group - A {@link CCNxManifestHashGroup} instance.
+ * @param [in] type - The {@link CCNxManifestHashGroupPointerType} type.
+ * @param [in] buffer - The {@link PARCBuffer} containing the pointer digest.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = CCNxManifestHashGroup_Create();
+ *
+ * PARCBuffer *hashDigest = ...;
+ *
+ * bool added = ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, hashDigest);
+ * // added == true if the group was not full
+ *
+ * CCNxManifestHashGroup_Release(&group);
+ * }
+ * @endcode
+ */
+bool ccnxManifestHashGroup_AppendPointer(CCNxManifestHashGroup *group, CCNxManifestHashGroupPointerType type, const PARCBuffer *buffer);
+
+/**
+ * Prepend a new pointer to the {@link CCNxManifestHashGroup} with the specified type and hash digest.
+ *
+ * @param [in] group - A {@link CCNxManifestHashGroup} instance.
+ * @param [in] type - The {@link CCNxManifestHashGroupPointerType} type.
+ * @param [in] buffer - The {@link PARCBuffer} containing the pointer digest.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = CCNxManifestHashGroup_Create();
+ *
+ * PARCBuffer *hashDigest = ...;
+ *
+ * bool added = ccnxManifestHashGroup_PrependPointer(group, CCNxManifestHashGroupPointerType_Data, hashDigest);
+ * // added == true if the group was not full
+ *
+ * CCNxManifestHashGroup_Release(&group);
+ * }
+ * @endcode
+ */
+bool ccnxManifestHashGroup_PrependPointer(CCNxManifestHashGroup *group, CCNxManifestHashGroupPointerType type, const PARCBuffer *buffer);
+
+/**
+ * Retrieve the {@link CCNxManifestHashGroupPointer} in the {@link CCNxManifestHashGroup} at
+ * the specified index.
+ *
+ * @param [in] group - A {@link CCNxManifestHashGroup} instance.
+ * @param [in] index - The index of the `CCNxManifestHashGroupPointer` to retrieve.
+ *
+ * @retval The `CCNxManifestHashGroupPointer` at the specified index.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = CCNxManifestHashGroup_Create();
+ *
+ * PARCBuffer *hashDigest = ...;
+ * ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, hashDigest);
+ *
+ * // ...
+ * CCNxManifestHashGroupPointer *pointer = ccnxManifestHashGroup_GetPointerAtIndex(group, 0);
+ * // use it as needed
+ *
+ * CCNxManifestHashGroup_Release(&group);
+ * }
+ * @endcode
+ */
+CCNxManifestHashGroupPointer *ccnxManifestHashGroup_GetPointerAtIndex(const CCNxManifestHashGroup *group, size_t index);
+
+/**
+ * Determine if two {@link CCNxManifestHashGroup} instances are equal.
+ *
+ * The following equivalence relations on non-null {@link CCNxManifestHashGroup} instances are maintained:
+ * * It is reflexive: for any non-null reference value x, `CCNxManifestHashGroup_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `CCNxManifestHashGroup_Equals(x, y)` must return true if and only if
+ * `CCNxManifestHashGroup_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `CCNxManifestHashGroup_Equals(x, y)` returns true and
+ * `CCNxManifestHashGroup_Equals(y, z)` returns true,
+ * then `CCNxManifestHashGroup_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `CCNxManifestHashGroup_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `CCNxManifestHashGroup_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] x A pointer to a {@link CCNxManifestHashGroup} instance.
+ * @param [in] y A pointer to a {@link CCNxManifestHashGroup} instance.
+ * @return `true` if the referenced {@link CCNxManifestHashGroup} instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *a = CCNxManifestHashGroup_Create(...);
+ * CCNxManifestHashGroup *b = CCNxManifestHashGroup_Create(...);
+ *
+ * if (CCNxManifestHashGroup_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool ccnxManifestHashGroup_Equals(const CCNxManifestHashGroup *x, const CCNxManifestHashGroup *y);
+
+/**
+ * Create a null-terminated string representation of the given {@link CCNxManifestHashGroup}.
+ *
+ * The returned value must be freed by the caller using {@link parcMemory_Deallocate()}.
+ *
+ * @param [in] group A pointer to a {@link CCNxManifestHashGroup} instance.
+ *
+ * @return A pointer to null-terminated string of characters repesenting the @p section that must be
+ * freed by the caller by `parcMemory_Deallocate()`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = CCNxManifestHashGroup_Create();
+ *
+ * char *sectionDescription = CCNxManifestHashGroup_ToString(group);
+ * printf("Manifest: %s\n", sectionDescription);
+ *
+ * CCNxManifestHashGroup_Release(&group);
+ * }
+ * @endcode
+ */
+char *ccnxManifestHashGroup_ToString(const CCNxManifestHashGroup *group);
+
+/**
+ * Create a `CCNxJson` representation of the given {@link CCNxManifestHashGroup}.
+ *
+ * The returned value must be freed by the caller using {@link ccnxJson_Destroy()}.
+ *
+ * @param [in] section A pointer to a {@link CCNxManifestHashGroup} instance.
+ *
+ * @return A pointer to the JSON representation of the @p section that must be freed by the caller by `ccnxJson_Destroy()`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = CCNxManifestHashGroup_Create();
+ *
+ * PARCJSON *jsonForm = CCNxManifestHashGroup_ToJson(group);
+ * printf("Manifest: %s\n", ccnxJson_ToString(jsonForm));
+ *
+ * CCNxManifestHashGroup_Release(&group);
+ * }
+ * @endcode
+ */
+PARCJSON *ccnxManifestHashGroup_ToJson(const CCNxManifestHashGroup *section);
+
+/**
+ * Set the {@link CCNxName} locator for this {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ * @param [in] locator A {@link CCNxName} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ * CCNxName *name = ccnxName_CreateFromURI("lci:/some/place");
+ *
+ * ccnxManifestHashGroup_setLocator(group, name);
+ * }
+ * @endcode
+ */
+void ccnxManifestHashGroup_SetLocator(CCNxManifestHashGroup *group, const CCNxName *locator);
+
+/**
+ * Retrieve the {@link CCNxName} locator for this {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] CCNxManifestHashGroup A {@link CCNxManifestHashGroup} instance.
+ *
+ * @return non-NULL The {@link CCNxName} locator for this {@link CCNxManifestHashGroup}.
+ * @return NULL There is no locator.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ *
+ * CCNxName *locator = ccnxManifestHashGroup_GetLocator(group);
+ * printf("Manifest Locator: %s\n", ccnxName_ToString(locator));
+ *
+ * CCNxManifestHashGroup_Release(&group);
+ * }
+ * @endcode
+ */
+const CCNxName *ccnxManifestHashGroup_GetLocator(const CCNxManifestHashGroup *group);
+
+/**
+ * Retrieve the number of pointers in this {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ *
+ * @retval The number of pointers in the {@link CCNxManifestHashGroup} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ *
+ * size_t numPointers = ccnxManifestHashGroup_GetNumberOfPointers(group);
+ * for (size_t i = 0; i < numPointers; i++) {
+ * // get i-th pointer and do something with it
+ * }
+ *
+ * CCNxManifestHashGroup_Release(&group);
+ * }
+ * @endcode
+ */
+size_t ccnxManifestHashGroup_GetNumberOfPointers(const CCNxManifestHashGroup *group);
+
+/**
+ * Determine if more pointers can be added to a {@link CCNxManifestHashGroup} instance.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ *
+ * @return true More space is available
+ * @return false The manifest is full.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ *
+ * size_t numPointers= ccnxManifestHashGroup_GetNumberOfPointers(group);
+ * for (size_t i = 0; i < numPointers; i++) {
+ * // get i-th pointer and do something with it
+ * }
+ *
+ * CCNxManifestHashGroup_Release(&group);
+ * }
+ * @endcode
+ */
+bool ccnxManifestHashGroup_IsFull(const CCNxManifestHashGroup *group);
+
+/**
+ * Retrieve a {@link PARCIterator} to walk over each of the {@link CCNxManifestHashGroupPointer}
+ * instances in the {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ *
+ * @retval A {@link PARCIterator} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ * PARCIterator *itr = ccnxManifestHashGroup_Iterator(group);
+ * while (parcIterator_HasNext(itr)) {
+ * CCNxManifestHashGroupPointer *ptr = (CCNxManifestHashGroupPointer *) parcIterator_Next(itr);
+ * // use the pointer
+ * }
+ * }
+ * @endcode
+ */
+PARCIterator *ccnxManifestHashGroup_Iterator(const CCNxManifestHashGroup *group);
+
+/**
+ * Retrieve the block size of this {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ *
+ * @retval The block size of the {@link CCNxManifestHashGroup} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ *
+ * size_t blockSize = ccnxManifestHashGroup_GetBlockSize(group);
+ * // use it
+ * }
+ * @endcode
+ */
+size_t ccnxManifestHashGroup_GetBlockSize(const CCNxManifestHashGroup *group);
+
+/**
+ * Set the block size of this {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ * @param [in] blockSize The block size.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ * size_t blockSize =
+ *
+ * ccnxManifestHashGroup_SetBlockSize(group, blockSize);
+ * }
+ * @endcode
+ */
+void ccnxManifestHashGroup_SetBlockSize(CCNxManifestHashGroup *group, size_t blockSize);
+
+/**
+ * Retrieve the data size of this {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ *
+ * @retval The data size of the {@link CCNxManifestHashGroup} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ *
+ * size_t dataSize = ccnxManifestHashGroup_GetDataSize(group);
+ * // use it
+ * }
+ * @endcode
+ */
+size_t ccnxManifestHashGroup_GetDataSize(const CCNxManifestHashGroup *group);
+
+/**
+ * Set the data size of this {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ * @param [in] dataSize The data size
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ * size_t dataSize =
+ *
+ * ccnxManifestHashGroup_SetDataSize(group, dataSize);
+ * }
+ * @endcode
+ */
+void ccnxManifestHashGroup_SetDataSize(CCNxManifestHashGroup *group, size_t dataSize);
+
+/**
+ * Retrieve the entry size of this {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ *
+ * @retval The entry size of the {@link CCNxManifestHashGroup} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ *
+ * size_t entrySize = ccnxManifestHashGroup_GetEntrySize(group);
+ * // use it
+ * }
+ * @endcode
+ */
+size_t ccnxManifestHashGroup_GetEntrySize(const CCNxManifestHashGroup *group);
+
+/**
+ * Set the entry size of this {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ * @param [in] entrySize The entry size.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ * size_t entrySize =
+ *
+ * ccnxManifestHashGroup_SetEntrySize(group, entrySize);
+ * }
+ * @endcode
+ */
+void ccnxManifestHashGroup_SetEntrySize(CCNxManifestHashGroup *group, size_t entrySize);
+
+/**
+ * Retrieve the tree height of this {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ *
+ * @retval The tree height of the {@link CCNxManifestHashGroup} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ *
+ * size_t treeHeight = ccnxManifestHashGroup_GetTreeHeight(group);
+ * // use it
+ * }
+ * @endcode
+ */
+size_t ccnxManifestHashGroup_GetTreeHeight(const CCNxManifestHashGroup *group);
+
+/**
+ * Set the tree height of this {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ * @param [in] treeHeight The tree height of the {@link CCNxManifestHashGroup} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ * size_t treeHeight = ...
+ * ccnxManifestHashGroup_SetTreeHeight(group, treeHeight);
+ * }
+ * @endcode
+ */
+void ccnxManifestHashGroup_SetTreeHeight(CCNxManifestHashGroup *group, size_t treeHeight);
+
+/**
+ * Retrieve the overall data digest of this {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ *
+ * @retval The overall data digest of the {@link CCNxManifestHashGroup} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ *
+ * const PARCBuffer *digest = ccnxManifestHashGroup_GetOverallDataDigest(group);
+ * // use it
+ * }
+ * @endcode
+ */
+const PARCBuffer *ccnxManifestHashGroup_GetOverallDataDigest(const CCNxManifestHashGroup *group);
+
+/**
+ * Set the overall data digest of this {@link CCNxManifestHashGroup}.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ * @param [in] digest The overall data digest of the {@link CCNxManifestHashGroup} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ * const PARCBuffer *digest = ...
+ *
+ * ccnxManifestHashGroup_SetOverallDataDigest(group, digest);
+ * }
+ * @endcode
+ */
+void ccnxManifestHashGroup_SetOverallDataDigest(CCNxManifestHashGroup *group, const PARCBuffer *digest);
+
+/**
+ * Determine if this `CCNxManifestHashGroup` is carrying any metadata.
+ *
+ * @param [in] group A {@link CCNxManifestHashGroup} instance.
+ *
+ * @retval true If the `CCNxManifestHashGroup` has metadata.
+ * @retval false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...
+ *
+ * bool hasMetadata = ccnxManifestHashGroup_HasMetadata(group);
+ * }
+ * @endcode
+ */
+bool ccnxManifestHashGroup_HasMetadata(const CCNxManifestHashGroup *group);
+
+/**
+ * Create a list of `CCNxInterest` instances that can be created from this single
+ * `CCNxManifestHashGroup` instance.
+ *
+ * @param [in] group A pointer to an instance of `CCNxManifestHashGroup`.
+ * @param [in] name A `CCNxName` locator for the interests in this list.
+ *
+ * @return A `PARCLinkedList` containing the set of all Interests that can be
+ * constructed from this HashGroup.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxManifestHashGroup *group = ...;
+ *
+ * PARCLinkedList *interests = ccnxManifestHashGroup_CreateInterestList(group);
+ * }
+ * @endcode
+ */
+PARCLinkedList *ccnxManifestHashGroup_CreateInterestList(const CCNxManifestHashGroup *group, const CCNxName *locator);
+#endif // libccnx_ccnx_ManifestHashGroup_h
diff --git a/libccnx-common/ccnx/common/ccnx_Name.c b/libccnx-common/ccnx/common/ccnx_Name.c
new file mode 100755
index 00000000..df4ead1b
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_Name.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/ccnx_Name.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_LinkedList.h>
+#include <parc/algol/parc_URI.h>
+#include <parc/algol/parc_URIPath.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+
+struct ccnx_name {
+ PARCLinkedList *segments;
+};
+
+static bool
+_ccnxName_Destructor(CCNxName **pointer)
+{
+ CCNxName *name = *pointer;
+
+ parcLinkedList_Release(&name->segments);
+ return true;
+}
+
+parcObject_Override(CCNxName, PARCObject,
+ .destructor = (PARCObjectDestructor *) _ccnxName_Destructor,
+ .copy = (PARCObjectCopy *) ccnxName_Copy,
+ .equals = (PARCObjectEquals *) ccnxName_Equals,
+ .compare = (PARCObjectCompare *) ccnxName_Compare,
+ .hashCode = (PARCObjectHashCode *) ccnxName_HashCode,
+ .toString = (PARCObjectToString *) ccnxName_ToString,
+ .display = (PARCObjectDisplay *) ccnxName_Display);
+CCNxName *
+ccnxName_Create(void)
+{
+ CCNxName *result = parcObject_CreateInstance(CCNxName);
+
+ if (result != NULL) {
+ result->segments = parcLinkedList_Create();
+ }
+
+ return result;
+}
+
+parcObject_ImplementAcquire(ccnxName, CCNxName);
+
+parcObject_ImplementRelease(ccnxName, CCNxName);
+
+void
+ccnxName_AssertValid(const CCNxName *name)
+{
+ trapIllegalValueIf(ccnxName_IsValid(name) == false, "CCNxName instance is not valid.");
+}
+
+bool
+ccnxName_IsValid(const CCNxName *name)
+{
+ bool result = false;
+
+ if (name != NULL) {
+ result = parcLinkedList_IsValid(name->segments);
+ }
+
+ return result;
+}
+
+CCNxName *
+ccnxName_Copy(const CCNxName *originalName)
+{
+ ccnxName_OptionalAssertValid(originalName);
+
+ CCNxName *result = ccnxName_Create();
+
+ if (result != NULL) {
+ for (int i = 0; i < ccnxName_GetSegmentCount(originalName); i++) {
+ CCNxNameSegment *component = ccnxName_GetSegment(originalName, i);
+ CCNxNameSegment *copy = ccnxNameSegment_Copy(component);
+ ccnxName_Append(result, copy);
+ ccnxNameSegment_Release(&copy);
+ }
+ }
+
+ return result;
+}
+
+bool
+ccnxName_Equals(const CCNxName *a, const CCNxName *b)
+{
+ if (a == b) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (ccnxName_GetSegmentCount(a) == ccnxName_GetSegmentCount(b)) {
+ return parcLinkedList_Equals(a->segments, b->segments);
+ }
+ return false;
+}
+
+CCNxName *
+ccnxName_CreateFormatString(const char *restrict format, ...)
+{
+ va_list argList;
+ va_start(argList, format);
+
+ PARCURI *uri = parcURI_CreateFromValist(format, argList);
+
+ CCNxName *result = ccnxName_FromURI(uri);
+ parcURI_Release(&uri);
+
+ return result;
+}
+
+CCNxName *
+ccnxName_FromURI(const PARCURI *uri)
+{
+ CCNxName *result = NULL;
+
+ PARCURIPath *path = parcURI_GetPath(uri);
+ if (path != NULL) {
+ result = ccnxName_Create();
+
+ for (int i = 0; i < parcURIPath_Count(path); i++) {
+ CCNxNameSegment *segment = ccnxNameSegment_ParseURISegment(parcURIPath_Get(path, i));
+ if (segment == NULL) {
+ ccnxName_Release(&result);
+ break;
+ }
+ parcLinkedList_Append(result->segments, segment);
+ ccnxNameSegment_Release(&segment);
+ }
+ }
+
+ return result;
+}
+
+CCNxName *
+ccnxName_CreateFromCString(const char *uri)
+{
+ CCNxName *result = NULL;
+
+ PARCURI *parcURI = parcURI_Parse(uri);
+ if (parcURI != NULL) {
+ const char *scheme = parcURI_GetScheme(parcURI);
+ if (strcmp("lci", scheme) == 0 || strcmp("ccnx", scheme) == 0) {
+ result = ccnxName_FromURI(parcURI);
+ }
+ parcURI_Release(&parcURI);
+ }
+
+ return result;
+}
+
+CCNxName *
+ccnxName_CreateFromBuffer(const PARCBuffer *buffer)
+{
+ char *string = parcBuffer_ToString(buffer);
+ CCNxName *result = ccnxName_CreateFromCString(string);
+ parcMemory_Deallocate(&string);
+
+ return result;
+}
+
+CCNxName *
+ccnxName_ComposeNAME(const CCNxName *name, const char *suffix)
+{
+ CCNxNameSegment *suffixSegment = ccnxNameSegment_CreateTypeValueArray(CCNxNameLabelType_NAME, strlen(suffix), suffix);
+
+ CCNxName *result = ccnxName_Append(ccnxName_Copy(name), suffixSegment);
+ ccnxNameSegment_Release(&suffixSegment);
+
+ return result;
+}
+
+CCNxName *
+ccnxName_Append(CCNxName *name, const CCNxNameSegment *segment)
+{
+ ccnxName_OptionalAssertValid(name);
+ ccnxNameSegment_OptionalAssertValid(segment);
+
+ parcLinkedList_Append(name->segments, segment);
+
+ return name;
+}
+
+PARCBufferComposer *
+ccnxName_BuildString(const CCNxName *name, PARCBufferComposer *composer)
+{
+ parcBufferComposer_PutString(composer, "ccnx:");
+
+ size_t count = ccnxName_GetSegmentCount(name);
+ if (count == 0) {
+ parcBufferComposer_PutString(composer, "/");
+ } else {
+ for (size_t i = 0; i < count; i++) {
+ parcBufferComposer_PutString(composer, "/");
+ CCNxNameSegment *component = ccnxName_GetSegment(name, i);
+ ccnxNameSegment_BuildString(component, composer);
+ }
+ }
+ return composer;
+}
+
+char *
+ccnxName_ToString(const CCNxName *name)
+{
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ ccnxName_BuildString(name, composer);
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ }
+
+ return result;
+}
+
+CCNxNameSegment *
+ccnxName_GetSegment(const CCNxName *name, size_t index)
+{
+ return parcLinkedList_GetAtIndex(name->segments, index);
+}
+
+size_t
+ccnxName_GetSegmentCount(const CCNxName *name)
+{
+ return parcLinkedList_Size(name->segments);
+}
+
+int
+ccnxName_Compare(const CCNxName *name1, const CCNxName *name2)
+{
+ if (name1 == NULL) {
+ if (name2 == NULL) {
+ return 0;
+ }
+ return -1;
+ }
+
+ // name1 is not NULL
+ if (name2 == NULL) {
+ return +1;
+ }
+
+ // neither is NULL
+
+ size_t name1SegmentCount = ccnxName_GetSegmentCount(name1);
+ size_t name2SegmentCount = ccnxName_GetSegmentCount(name2);
+
+ size_t mininimumSegments = name1SegmentCount < name2SegmentCount ? name1SegmentCount : name2SegmentCount;
+
+ int result = 0;
+
+ for (size_t i = 0; i < mininimumSegments; i++) {
+ CCNxNameSegment *segment1 = ccnxName_GetSegment(name1, i);
+ CCNxNameSegment *segment2 = ccnxName_GetSegment(name2, i);
+ result = ccnxNameSegment_Compare(segment1, segment2);
+ if (result != 0) {
+ break;
+ }
+ }
+
+ if (result == 0) {
+ // we got to the end of the shortest name and they are still equal.
+
+ // name1 is shorter than name 2
+ if (name1SegmentCount < name2SegmentCount) {
+ result = -1;
+ }
+
+ // name1 is longer than name2
+ if (name1SegmentCount > name2SegmentCount) {
+ result = +1;
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+ccnxName_HashCode(const CCNxName *name)
+{
+ return ccnxName_LeftMostHashCode(name, ccnxName_GetSegmentCount(name));
+}
+
+PARCHashCode
+ccnxName_LeftMostHashCode(const CCNxName *name, size_t count)
+{
+ if (count > ccnxName_GetSegmentCount(name)) {
+ count = ccnxName_GetSegmentCount(name);
+ }
+
+ PARCHashCode result = 0;
+ for (int i = 0; i < count; i++) {
+ PARCHashCode hashCode = ccnxNameSegment_HashCode(ccnxName_GetSegment(name, i));
+ result = parcHashCode_HashHashCode(result, hashCode);
+ }
+
+ return result;
+}
+
+CCNxName *
+ccnxName_Trim(CCNxName *name, size_t numberToRemove)
+{
+ if (numberToRemove > ccnxName_GetSegmentCount(name)) {
+ numberToRemove = ccnxName_GetSegmentCount(name);
+ }
+
+ for (int i = 0; i < numberToRemove; i++) {
+ CCNxNameSegment *segment = parcLinkedList_RemoveLast(name->segments);
+ ccnxNameSegment_Release(&segment);
+ }
+
+ return name;
+}
+
+bool
+ccnxName_StartsWith(const CCNxName *name, const CCNxName *prefix)
+{
+ if (ccnxName_GetSegmentCount(prefix) > ccnxName_GetSegmentCount(name)) {
+ return false;
+ }
+
+ for (int i = 0; i < ccnxName_GetSegmentCount(prefix); i++) {
+ CCNxNameSegment *prefix_comp = ccnxName_GetSegment(prefix, i);
+ CCNxNameSegment *other_comp = ccnxName_GetSegment(name, i);
+
+ if (ccnxNameSegment_Compare(prefix_comp, other_comp) != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void
+ccnxName_Display(const CCNxName *name, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "CCNxName@%p {", name);
+ if (name != NULL) {
+ for (int i = 0; i < ccnxName_GetSegmentCount(name); i++) {
+ CCNxNameSegment *segment = ccnxName_GetSegment(name, i);
+ ccnxNameSegment_Display(segment, indentation + 1);
+ }
+ }
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+CCNxName *
+ccnxName_ComposeFormatString(const CCNxName *baseName, const char *restrict format, ...)
+{
+ va_list argList;
+ va_start(argList, format);
+
+ char *baseString = ccnxName_ToString(baseName);
+
+ char *suffix;
+ vasprintf(&suffix, format, argList);
+
+ char *uri;
+ asprintf(&uri, "%s/%s", baseString, suffix);
+ free(suffix);
+
+ CCNxName *result = ccnxName_CreateFromCString(uri);
+ free(uri);
+
+ return result;
+}
+
+CCNxName *
+ccnxName_CreatePrefix(const CCNxName *name, size_t length)
+{
+ CCNxName *result = ccnxName_Create();
+
+ if (result != NULL) {
+ if (length > 0) {
+ size_t numberOfSegmentsAvailable = parcLinkedList_Size(name->segments);
+
+ if (length > numberOfSegmentsAvailable) {
+ length = numberOfSegmentsAvailable;
+ }
+
+ for (size_t i = 0; i < length; i++) {
+ ccnxName_Append(result, ccnxName_GetSegment(name, i));
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/libccnx-common/ccnx/common/ccnx_Name.h b/libccnx-common/ccnx/common/ccnx_Name.h
new file mode 100755
index 00000000..83cb78ff
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_Name.h
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_Name.h
+ * @ingroup Naming
+ * @brief The basic CCNx Name.
+ *
+ * This implements an RFC3986 URI compliant identifier in which each path segment carries a label.
+ * This allows differentiation between resources with otherwise similar identifiers that are not related.
+ * For example, one resource could be named `"/parc/csl/7"` meaning the 7th version of `"/parc/csl"`,
+ * while another could mean the 7th page of the resource.
+ * With labeled segments, the two resources would have unambiguous names,
+ * such as `"/parc/csl/version=7"` and `"/parc/csl/page=7"`.
+ *
+ */
+#ifndef libccnx_ccnx_Name_h
+#define libccnx_ccnx_Name_h
+
+#include <parc/algol/parc_HashCode.h>
+#include <ccnx/common/ccnx_NameSegment.h>
+
+struct ccnx_name;
+/**
+ * @typedef CCNxName
+ * @brief An RFC3986 URI compliant identifier in which each path segment carries a label.
+ */
+typedef struct ccnx_name CCNxName;
+
+/**
+ * Create a new instance of `CCNxName`, initialized from the given string representation of an LCI URI,
+ * using dynamically allocated memory.
+ *
+ * The URI must be a well-formed URI.
+ *
+ * The `CCNxName` instance must be released by calling {@link ccnxName_Release}.
+ *
+ * @param [in] uri A null-terminated string representation of the CCNx Name.
+ * @return non-NULL A pointer to a `CCNxName` instance initialised from the given URI.
+ * @return NULL An error occured parsing the URI, or the URI contained an invalid specification.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/media/h2162");
+ *
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ */
+CCNxName *ccnxName_CreateFromCString(const char *uri);
+
+/**
+ * Create a new instance of `CCNxName`, initialized from the given `PARCURI` representation of an LCI URI,
+ * using dynamically allocated memory.
+ *
+ * The URI must be a well-formed LCI URI.
+ *
+ * The `CCNxName` instance must be released by calling {@link ccnxName_Release}.
+ *
+ * @param [in] uri A valid instance of PARCURI.
+ * @return non-NULL A pointer to a `CCNxName` instance initialised from the given URI.
+ * @return NULL An error occured parsing the URI, or the URI contained an invalid specification.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURI *uri = parcURI_Parse("lci:/parc/csl/media/h2162");
+ * CCNxName *name = ccnxName_CreateFromCString(uri);
+ *
+ * parcURI_Release(&uri);
+ *
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ */
+CCNxName *ccnxName_FromURI(const PARCURI *uri);
+
+/**
+ * Create a new instance of `CCNxName` from the given format string and variable number of parameters.
+ *
+ * @param [in] format A pointer to a nul-terminated printf format string
+ * @param [in] ... A variable number of parameters.
+ *
+ * @return non-NULL A pointer to a valid CCNxName instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFormatString("lci://%s/object", "parc.com");
+ * }
+ * @endcode
+ */
+CCNxName *ccnxName_CreateFormatString(const char *restrict format, ...);
+
+/**
+ * Create a new instance of `CCNxName`, initialized from a string representation of a LCI URI contained in the given PARCBuffer,
+ * starting at the current position and terminating with a zero-byte in the buffer.
+ * using dynamically allocated memory.
+ *
+ * The URI must be a well-formed URI.
+ *
+ * The `CCNxName` instance must be released by calling {@link ccnxName_Release}.
+ *
+ * @param [in] uri A null-terminated string representation of the CCNx Name.
+ * @return non-NULL A pointer to a `CCNxName` instance initialised from the given URI.
+ * @return NULL An error occured parsing the URI, or the URI contained an invalid specification.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_AllocateCString("lci:/parc/csl/media/h2162");
+ * CCNxName *name = ccnxName_CreateFromBuffer(buffer);
+ *
+ * ccnxName_Release(&name);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+CCNxName *ccnxName_CreateFromBuffer(const PARCBuffer *buffer);
+
+/**
+ * Increase the number of references to a `CCNxName` instance.
+ *
+ * Note that new `CCNxName` is not created,
+ * only that the given `CCNxName` reference count is incremented.
+ * Discard the reference by invoking {@link ccnxName_Release}.
+ *
+ * @param [in] name A pointer to the original `CCNxName`.
+ * @return The value of the input parameter @p name.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *original = ccnxName_Create();
+ *
+ * CCNxName *reference = ccnxName_Acquire(original);
+ *
+ * ccnxName_Release(&original);
+ * ccnxName_Release(&reference);
+ * }
+ * @endcode
+ *
+ * @see ccnxName_Release
+ */
+CCNxName *ccnxName_Acquire(const CCNxName *name);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] nameP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_Create(...);
+ *
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxName_Acquire}
+ */
+void ccnxName_Release(CCNxName **nameP);
+
+#ifdef Libccnx_DISABLE_VALIDATION
+# define ccnxName_OptionalAssertValid(_instance_)
+#else
+# define ccnxName_OptionalAssertValid(_instance_) ccnxName_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that an instance of `CCNxName` is valid.
+ *
+ * If the instance is not valid, terminate via {@link trapIllegalValue}
+ *
+ * Valid means the internal state of the type is consistent with its
+ * required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] name A pointer to a `CCNxName` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/ccn/things/p1e");
+ *
+ * ccnxName_AssertValid(name);
+ *
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ */
+void ccnxName_AssertValid(const CCNxName *name);
+
+/**
+ * Determine if an instance of `CCNxName` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its
+ * required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] name A pointer to a `CCNxName` instance.
+ * @return true If the instance is valid.
+ * @return false if the instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/ccn/things/p1e");
+ *
+ * if (ccnxName_IsValid(name) == true) {
+ * ...
+ * }
+ *
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ */
+bool ccnxName_IsValid(const CCNxName *name);
+
+/**
+ * Append a representation of the specified `CCNxName` instance to the given
+ * {@link PARCBufferComposer}.
+ *
+ * The CCN URI representing the {@link CCNxNameSegment}'s associated with this `CCNxName` is
+ * appended to the supplied {@link PARCBufferComposer}.
+ *
+ * @param [in] name A pointer to a `CCNxName` instance whose representation should be appended to the @p composer.
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance to be modified.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * ccnxName_BuildString(instance, result);
+ *
+ * char *string = parcBuffer_ToString(parcBufferComposer_ProduceBuffer(result));
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate(string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ *
+ * @see `CCNxNameSegment`
+ */
+PARCBufferComposer *ccnxName_BuildString(const CCNxName *name, PARCBufferComposer *composer);
+
+/**
+ * Produce a null-terminated string representation of the specified instance.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] name A pointer to the `CCNxName` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated,
+ * null-terminated C string that must be deallocated via `parcMemory_Deallocate()`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *instance = ccnxName_Create();
+ *
+ * char *string = ccnxName_ToString(instance);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate(string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * ccnxName_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxName_BuildString}
+ * @see {@link ccnxName_Display}
+ * @see {@link parcMemory_Deallocate}
+ */
+char *ccnxName_ToString(const CCNxName *name);
+
+/**
+ * Print a human readable representation of the given `CCNxName`.
+ *
+ * @param [in] name A pointer to the `CCNxName` to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/11");
+ *
+ * ccnxInterest_Display(name, 0);
+ *
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ */
+void ccnxName_Display(const CCNxName *name, int indentation);
+
+/**
+ * Append a {@link CCNxNameSegment} to the given `CCNxName`.
+ *
+ * Append the `CCNxNameSegment` to the given `CCNxName`.
+ * The given `CCNxName` is modified.
+ *
+ * @param [in,out] name The base `CCNxName` to append the @p segment to.
+ * @param [in] segment The segment to append to @p name.
+ * @return The modifed @p name.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name1 = ccnxName_CreateFromCString("lci:/a/b/c/d");
+ * CCNxName *name2 = ccnxName_Create();
+ *
+ * CCNxNameSegment *segment = ccnxName_GetSegment(name1, 0);
+ *
+ * ccnxName_Append(name2, segment);
+ *
+ * ccnxName_Release(&name1);
+ * ccnxName_Release(&name2);
+ * }
+ * @endcode
+ */
+CCNxName *ccnxName_Append(CCNxName *name, const CCNxNameSegment *segment);
+
+/**
+ * Determine if a `CCNxName` is starts with another.
+ *
+ * Each {@link CCNxNameSegment} in @p prefix is tested against the corresponding `CCNxNameSegment`
+ * in @p name.
+ *
+ * @param [in] name A pointer to a `CCNxName` instance.
+ * @param [in] prefix A pointer to a `CCNxName` instance to be tested as a prefix of `name`.
+ *
+ * @return `true` If the given @p name starts with @p prefix.
+ * @return `false` If the given @p name does not start with @p prefix.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/17");
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/parc/csl");
+ *
+ * if (ccnxName_StartsWith(name, prefix)) {
+ * ...
+ * }
+ *
+ * ccnxName_Release(&name);
+ * ccnxName_Release(&prefix);
+ * }
+ * @endcode
+ */
+bool ccnxName_StartsWith(const CCNxName *name, const CCNxName *prefix);
+
+/**
+ * Create a copy of the specified `CCNxName` instance, producing a new, independent, instance
+ * from dynamically allocated memory.
+ *
+ * This a deep copy. All referenced memory is copied. The created instance of `CCNxName` must
+ * be released by calling {@link ccnxName_Release}().
+ *
+ * @param [in] originalName The `CCNxName` to copy
+ * @return A new, independent copy of the given `CCNxName`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *originalName = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/17");
+ * CCNxName *copy = ccnxName_Copy(originalName);
+ *
+ * ...
+ *
+ * ccnxName_Release(&originalName);
+ * ccnxName_Release(&copy);
+ * }
+ * @endcode
+ */
+CCNxName *ccnxName_Copy(const CCNxName *originalName);
+
+/**
+ * Determine if two `CCNxName` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxName` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `ccnxName_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxName_Equals(x, y)` must return true if and only if
+ * `ccnxName_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxName_Equals(x, y)` returns true and
+ * `ccnxName_Equals(y, z)` returns true,
+ * then `ccnxName_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxName_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxName_Equals(x, NULL)` must return false.
+ *
+ * @param [in] name1 A pointer to a `CCNxName` instance.
+ * @param [in] name2 A pointer to a `CCNxName` instance.
+ *
+ * @return True If the given `CCNxName` instances are equal
+ * @return False Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *orig = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/17");
+ * CCNxName *copy = ccnxName_Copy(orig);
+ *
+ * if (ccnxName_Equals(orig, copy)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * ccnxName_Release(&orig);
+ * ccnxName_Release(&copy);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxName_Compare}
+ */
+bool ccnxName_Equals(const CCNxName *name1, const CCNxName *name2);
+
+/**
+ * Create a new `CCNxName` object
+ *
+ * The instance is reference counted with an initial count of 1.
+ * Additional references are acquired via the function {@link ccnxName_Acquire}
+ * and these references are inidividually released via {@link ccnxName_Release}
+ *
+ * @return A pointer to a new instance of a `CCNxName`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_Create();
+ *
+ * ...
+ *
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ */
+CCNxName *ccnxName_Create(void);
+
+/**
+ * Compare @p name1 to @p name2 using CCNx canonical ordering (shortlex).
+ *
+ * `NULL` is considered the shortest name, so `(NULL, non-NULL) -> -1` and
+ * `(NULL, NULL) -> 0`, `(non-NULL, NULL) -> +1`.
+ *
+ * @param [in] name1 A pointer to a `CCNxName` instance.
+ * @param [in] name2 A pointer to a `CCNxName` instance.
+ *
+ * Returns:
+ * <ul>
+ * <li>-1 for name1 < name2</li>
+ * <li> 0 for name1 = name2</li>
+ * <li>+1 for name1 > name2</li>
+ * </ul>
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *orig = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/17");
+ * CCNxName *copy = ccnxName_Copy(orig);
+ *
+ * if (ccnxName_Compare(orig, copy)) {
+ * ...
+ * }
+ *
+ * ccnxName_Release(&orig);
+ * ccnxName_Release(&copy);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxName_Equals}
+ */
+int ccnxName_Compare(const CCNxName *name1, const CCNxName *name2);
+
+/**
+ * Return a pointer to the {@link CCNxNameSegment} instance for the specified `CCNxName` at the given index.
+ * The index must be greater than or equal to zero and less than {@link ccnxName_GetSegmentCount}().
+ *
+ * @param [in] name The target `CCNxName`
+ * @param [in] index The index into the @p name from which to retrieve the `CCNxNameSegment`.
+ *
+ * @return A pointer to a `CCNxNameSegment`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/things/b00se");
+ * CCNxNameSegment *segment2 = ccnxName_GetSegment(name, 2);
+ *
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ */
+CCNxNameSegment *ccnxName_GetSegment(const CCNxName *name, size_t index);
+
+/**
+ * Get the number of `CCNxNameSegments` in the specified `CCNxName`.
+ *
+ * @param [in] name A pointer to an instance of `CCNxName`.
+ *
+ * @return The number of name segments in @p name.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/things/b00se");
+ * size_t segmentCount = ccnxName_GetSegmentCount(name);
+ *
+ * printf("Number of segments: %d\n", segmentCount);
+ *
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ */
+size_t ccnxName_GetSegmentCount(const CCNxName *name);
+
+/**
+ * Return a hashcode for the given `CCNxName`.
+ *
+ * Whenever `HashCode()` is invoked on the same object more than once within the same execution environment,
+ * the HashCode function must consistently return the same integer, provided no information used in Equals()
+ * comparisons on the same object is modified.
+ *
+ * This integer need not remain consistent from one execution of an application to another execution of the same application.
+ *
+ * If two objects are equal according to the Equals() function,
+ * then calling the hashCode method on each of the two objects must produce the same integer result.
+ *
+ * It is not required that if two objects are unequal according to the Equals() function,
+ * then calling the Equals() method on each of the two objects must produce distinct integer results.
+ * However, the programmer should be aware that producing distinct integer results for unequal objects
+ * may improve the performance of some data structures.
+ *
+ * @param name [in] A pointer to an instance of `CCNxName`.
+ * @return A uint32_t hash code.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/ccn/things/r00");
+ *
+ * uint32_t hashCode = ccnx_LeftMostHashCode(name);
+ *
+ * ccnxName_Release(&name);
+ * {
+ * @endcode
+ */
+PARCHashCode ccnxName_HashCode(const CCNxName *name);
+
+/**
+ * Return a hash of the leftmost @p count {@link CCNxNameSegment}s in a `CCNxName`.
+ *
+ * See @{link ccnxName_HashCode} for more information.
+ *
+ * @param [in] name A pointer to a `CCNxName` instance.
+ * @param [in] count The number, starting from the left, of path segments to use to compute the hash.
+ *
+ * @return A uint32_t hash code.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/ccn/things/r00");
+ *
+ * uint32_t hashCode = ccnx_LeftMostHashCode(name, 2);
+ *
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ */
+PARCHashCode ccnxName_LeftMostHashCode(const CCNxName *name, size_t count);
+
+/**
+ * Trim @p numberToRemove segments from the end of the specified `CCNxName`.
+ *
+ * If @p numberToRemove is greater than the number of segments in the name,
+ * all segments are removed.
+ * If @p numberToRemove is 0, nothing happens.
+ * The name segments are destroyed.
+ *
+ * @param [in,out] name A pointer to a `CCNxName` instance to trim.
+ * @param [in] numberToRemove The number of rightmost segments to remove from the name.
+ *
+ * @return The value of @p name
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/ccn/things/b00se");
+ *
+ * name = ccnxName_Trim(name, 2);
+ *
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ *
+ */
+CCNxName *ccnxName_Trim(CCNxName *name, size_t numberToRemove);
+
+/**
+ * Compose a new CCNxName instance consisting of the given @prefix appended with @p suffix as a `CCNxNameLabelType_NAME`.
+ *
+ * @param [in] prefix A pointer to a valid CCNxName instance containing the prefix of the new name.
+ * @param [in] suffix A pointer to a nul-terminated C string that is appended to the new name.
+ *
+ * @return non-NULL A pointer to a valid CCNxName instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+CCNxName *ccnxName_ComposeNAME(const CCNxName *prefix, const char *suffix);
+
+
+/**
+ * Get the Nth segment number of the given `CCNxName`
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] name A pointer to a valid `CCNxName` instance.
+ * @param [in] nthNumber The nth segment number in the given name, or SIZE_MAX
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint64_t ccnxName_GetNthSegmentNumber(const CCNxName *name, size_t nthNumber);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint64_t ccnxName_GetSegmentNumber(const CCNxName *name);
+
+/**
+ * Create a new CCNxName instance composed of the given CCNxName with the parsed result of the format string appended.
+ *
+ * @param [in] baseName The base name of the new CCNxName
+ * @param [in] format A printf(3) format string
+ *
+ * @return non-NULL A pointer to a valid `CCNxName` segment.
+ * @return NULL The object could not be created.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+CCNxName *ccnxName_ComposeFormatString(const CCNxName *baseName, const char *restrict format, ...);
+
+/**
+ * Create a CCNxName that is a prefix of another.
+ *
+ * If the specified length is greater than the number of segments available,
+ * the result is a new name that is a copy of the old name.
+ *
+ * @param [in] name A pointer to a valid `CCNxName` instance.
+ * @param [in] length The number of `CCNxNameSegments` the prefix must include.
+ *
+ * @return non-NULL A pointer to a valid CCNxName.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *a = ccnxName_CreateFromCString("ccnx:/a/b/c");
+ *
+ * CCNxName *prefix = ccnxName_CreatePrefix(a, 1);
+ *
+ * // prefix is equal to the name "ccnx:/a"
+ *
+ * ccnxName_Release(&a);
+ * ccnxName_Release(&prefix);
+ * ccnxName_Release(&actual);
+ * }
+ * @endcode
+ */
+CCNxName *ccnxName_CreatePrefix(const CCNxName *name, size_t length);
+#endif // libccnx_ccnx_Name_h
diff --git a/libccnx-common/ccnx/common/ccnx_NameLabel.c b/libccnx-common/ccnx/common/ccnx_NameLabel.c
new file mode 100755
index 00000000..290e6069
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_NameLabel.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <ctype.h>
+
+#include <parc/algol/parc_Object.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/ccnx_NameLabel.h>
+
+struct ccnx_name_label {
+ CCNxNameLabelType type;
+ PARCBuffer *parameter;
+};
+
+static struct CCNxNameLabelMnemonic {
+ const char *mnemonic;
+ const CCNxNameLabelType type;
+} CCNxNameLabelMnemonic[] = {
+ { CCNxNameLabel_Name, CCNxNameLabelType_NAME },
+ { CCNxNameLabel_InterestPayloadId, CCNxNameLabelType_PAYLOADID },
+ { CCNxNameLabel_Serial, CCNxNameLabelType_SERIAL },
+ { CCNxNameLabel_Chunk, CCNxNameLabelType_CHUNK },
+ { CCNxNameLabel_ChunkMeta, CCNxNameLabelType_CHUNKMETA },
+ { CCNxNameLabel_App, CCNxNameLabelType_APP0 },
+ { CCNxNameLabel_Time, CCNxNameLabelType_TIME },
+ { NULL, CCNxNameLabelType_Unknown },
+};
+
+static bool
+_ccnxNameLabel_Destructor(CCNxNameLabel **labelP)
+{
+ assertNotNull(labelP, "Parameter must be a non-null pointer to a CCNxNameLabels pointer.");
+
+ CCNxNameLabel *label = *labelP;
+ if (label->parameter != NULL) {
+ parcBuffer_Release(&label->parameter);
+ }
+ return true;
+}
+
+parcObject_Override(CCNxNameLabel, PARCObject,
+ .destructor = (PARCObjectDestructor *) _ccnxNameLabel_Destructor);
+
+parcObject_ImplementAcquire(ccnxNameLabel, CCNxNameLabel);
+
+parcObject_ImplementRelease(ccnxNameLabel, CCNxNameLabel);
+
+CCNxNameLabel *
+ccnxNameLabel_Create(CCNxNameLabelType type, const PARCBuffer *parameter)
+{
+ CCNxNameLabel *result = NULL;
+
+ if (type != CCNxNameLabelType_BADNAME && type != CCNxNameLabelType_Unknown) {
+ result = parcObject_CreateInstance(CCNxNameLabel);
+ if (result != NULL) {
+ result->type = type;
+ result->parameter = parameter == NULL ? NULL : parcBuffer_Acquire(parameter);
+ }
+ }
+
+ return result;
+}
+
+CCNxNameLabelType
+ccnxNameLabel_GetType(const CCNxNameLabel *label)
+{
+ ccnxNameLabel_OptionalAssertValid(label);
+
+ return label->type;
+}
+
+PARCBuffer *
+ccnxNameLabel_GetParameter(const CCNxNameLabel *label)
+{
+ ccnxNameLabel_OptionalAssertValid(label);
+ return label->parameter;
+}
+
+static const char *
+_ccnxNameLabelType_ToMnemonic(CCNxNameLabelType type)
+{
+ const char *result = NULL;
+
+ for (struct CCNxNameLabelMnemonic *p = &CCNxNameLabelMnemonic[0]; p->mnemonic != NULL; p++) {
+ if (p->type == type) {
+ result = p->mnemonic;
+ break;
+ }
+ }
+
+ return result;
+}
+
+static CCNxNameLabelType
+_ccnxNameLabelType_ResolveNumeric(PARCBuffer *label)
+{
+ CCNxNameLabelType result = (CCNxNameLabelType) parcBuffer_ParseNumeric(label);
+
+ return result;
+}
+
+static CCNxNameLabelType
+_ccnxNameLabelType_ResolveMnemonic(const PARCBuffer *label)
+{
+ CCNxNameLabelType result = CCNxNameLabelType_Unknown;
+
+ size_t labelLength = parcBuffer_Remaining(label);
+ char *labelAsBytes = parcBuffer_Overlay((PARCBuffer *) label, 0);
+
+ for (struct CCNxNameLabelMnemonic *p = &CCNxNameLabelMnemonic[0]; p->mnemonic != NULL; p++) {
+ if (strncasecmp(p->mnemonic, labelAsBytes, labelLength) == 0) {
+ result = p->type;
+ break;
+ }
+ }
+
+ return result;
+}
+
+static CCNxNameLabelType
+_ccnxNameLabelType_Resolve(PARCBuffer *label)
+{
+ CCNxNameLabelType result = CCNxNameLabelType_NAME;
+
+ if (label != NULL) {
+ if (parcBuffer_Remaining(label) > 0) {
+ if (isdigit(parcBuffer_PeekByte(label))) {
+ result = _ccnxNameLabelType_ResolveNumeric(label);
+ } else {
+ result = _ccnxNameLabelType_ResolveMnemonic(label);
+ }
+ } else {
+ result = CCNxNameLabelType_NAME;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Parse the 'label [":" param] ' portion of an lpv-segment
+ *
+ * lpv-segment = label [":" param] "=" s-value
+ * v-segment = s-value
+ * label = alpha-t / num-t
+ * param = alpha-t / num-t
+ * s-value = *(s-pchar)
+ *
+ * number =
+ * number
+ */
+CCNxNameLabel *
+ccnxNameLabel_Parse(PARCBuffer *buffer)
+{
+ PARCBuffer *label = NULL;
+ PARCBuffer *parameter = NULL;
+
+ // When complete, the buffer's position will be set to the first byte of the value portion.
+ if (parcBuffer_SkipTo(buffer, 1, (uint8_t *) "=")) {
+ label = parcBuffer_Flip(parcBuffer_Duplicate(buffer));
+ if (parcBuffer_Remaining(label) > 0) {
+ parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) + 1);
+
+ if (parcBuffer_SkipTo(label, 1, (uint8_t *) ":")) {
+ size_t colon = parcBuffer_Position(label);
+ parcBuffer_SetPosition(label, colon + 1);
+ parameter = parcBuffer_Slice(label);
+
+ parcBuffer_SetPosition(label, colon);
+ }
+
+ label = parcBuffer_Flip(label);
+ } else {
+ parcBuffer_Release(&label);
+ return NULL;
+ }
+ } else {
+ parcBuffer_Rewind(buffer);
+ }
+
+ CCNxNameLabelType type = CCNxNameLabelType_NAME;
+
+ if (label != NULL) {
+ type = _ccnxNameLabelType_Resolve(label);
+ if (type == CCNxNameLabelType_App(0)) {
+ if (parameter != NULL) {
+ type = CCNxNameLabelType_App(parcBuffer_ParseNumeric(parameter));
+ parcBuffer_Release(&parameter);
+ }
+ }
+ parcBuffer_Release(&label);
+ }
+
+ CCNxNameLabel *result = ccnxNameLabel_Create(type, parameter);
+
+ if (parameter != NULL) {
+ parcBuffer_Release(&parameter);
+ }
+
+ return result;
+}
+
+bool
+ccnxNameLabel_Equals(const CCNxNameLabel *x, const CCNxNameLabel *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (x->type == y->type) {
+ if (parcBuffer_Equals(x->parameter, y->parameter)) {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+CCNxNameLabel *
+ccnxNameLabel_Copy(const CCNxNameLabel *label)
+{
+ ccnxNameLabel_OptionalAssertValid(label);
+
+ PARCBuffer *parameter = (label->parameter == NULL) ? NULL : parcBuffer_Copy(label->parameter);
+ CCNxNameLabel *result = ccnxNameLabel_Create(label->type, parameter);
+ if (parameter != NULL) {
+ parcBuffer_Release(&parameter);
+ }
+
+ return result;
+}
+
+bool
+ccnxNameLabel_IsValid(const CCNxNameLabel *label)
+{
+ bool result = false;
+
+ if (label != NULL) {
+ if (label->type != CCNxNameLabelType_Unknown && label->type != CCNxNameLabelType_BADNAME) {
+ if (label->parameter != NULL) {
+ if (parcBuffer_IsValid(label->parameter)) {
+ result = true;
+ }
+ } else {
+ result = true;
+ }
+ }
+ }
+ return result;
+}
+
+void
+ccnxNameLabel_AssertValid(const CCNxNameLabel *label)
+{
+ trapIllegalValueIf(ccnxNameLabel_IsValid(label) == false, "Encountered an invalid CCNxNameLabel instance.");
+}
+
+PARCBufferComposer *
+ccnxNameLabel_BuildString(const CCNxNameLabel *label, PARCBufferComposer *composer)
+{
+ ccnxNameLabel_OptionalAssertValid(label);
+
+ if (label->type >= CCNxNameLabelType_App(0) && label->type <= CCNxNameLabelType_App(4096)) {
+ parcBufferComposer_Format(composer, "%s:%u=", CCNxNameLabel_App, label->type - CCNxNameLabelType_App(0));
+ } else {
+ const char *mnemonic = _ccnxNameLabelType_ToMnemonic(label->type);
+ if (mnemonic == NULL) {
+ parcBufferComposer_Format(composer, "%u", label->type);
+ } else {
+ parcBufferComposer_PutString(composer, mnemonic);
+ }
+
+ if (label->parameter != NULL) {
+ parcBufferComposer_PutString(composer, ":");
+ parcBufferComposer_PutBuffer(composer, label->parameter);
+ }
+ parcBufferComposer_PutString(composer, "=");
+ }
+
+ return composer;
+}
+
+char *
+ccnxNameLabel_ToString(const CCNxNameLabel *label)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ ccnxNameLabel_BuildString(label, composer);
+
+ char *result = parcBufferComposer_ToString(composer);
+
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
diff --git a/libccnx-common/ccnx/common/ccnx_NameLabel.h b/libccnx-common/ccnx/common/ccnx_NameLabel.h
new file mode 100755
index 00000000..5a4ff324
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_NameLabel.h
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_NameLabel.h
+ * @ingroup Naming
+ * @brief The possible types of CCNx Name Segments, and utilities to extract and encode them.
+ *
+ * Every CCNxName is comprised of CCNxNameSegments, and each CCNxNameSegment has a type associated with it.
+ * For example, it may specify a simple name (`CCNxNameLabelType_NAME`),
+ * content chunk numbers (`CCNxNameLabelType_CHUNK`), or any other type defined in `CCNxNameLabelType`.
+ *
+ * The type of a name is comprised of a label and an option parameter.
+ * The label may be a decimal or hexadecimal representation of the type value, or a mnemonic like "Name", "Serial".
+ *
+ */
+#ifndef libccnx_ccnx_NameType_h
+#define libccnx_ccnx_NameType_h
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+#define CCNxNameLabelType_APP0 ((CCNxNameLabelType) 0x1000)
+#define CCNxNameLabelType_APP4096 ((CCNxNameLabelType) (CCNxNameLabelType_APP0 + 4096))
+
+/**
+ * Compose a CCNx Name Label Type in the Application-specific type space.
+ */
+#define CCNxNameLabelType_App(_n_) (CCNxNameLabelType_APP0 + (CCNxNameLabelType) _n_)
+
+/**
+ * @typedef CCNxNameLabelType
+ * @brief An enumeration of possible CCNxName types.
+ */
+typedef enum {
+ CCNxNameLabelType_BADNAME = 0x0000,
+ CCNxNameLabelType_NAME = 0x0001, // Name: CCNx Messages in TLV Format
+ CCNxNameLabelType_PAYLOADID = 0x0002, // Payload Hash: CCNx Messages in TLV Format
+ CCNxNameLabelType_BINARY = 0x0003, // Binary segment
+ CCNxNameLabelType_CHUNK = 0x0010, // Segment Number: CCNx Content Object Segmentation
+ CCNxNameLabelType_CHUNKMETA = 0x0011, // Metadata
+ CCNxNameLabelType_TIME = 0x0012, // Time: CCNx Publisher Serial Versioning
+ CCNxNameLabelType_SERIAL = 0x0013, // Serial Number: CCNx Publisher Serial Versioning
+ CCNxNameLabelType_Unknown = 0xfffff
+} CCNxNameLabelType;
+
+/**
+ * These definitions should agree with the CCNxNameLabelType enumeration to avoid confusion.
+ * These definitions must agree with the specification and with the CCNxNameLabelType_String definitions.
+ *
+ * Use these definition in constructing string representations of names.
+ * For example "lci://" CCNxNameLabel_Serial "/1"
+ *
+ * @def CCNxNameLabelType_NameLabel The name
+ */
+#define CCNxNameLabel_Name "Name"
+#define CCNxNameLabel_InterestPayloadId "PayloadId"
+#define CCNxNameLabel_Chunk "Chunk"
+#define CCNxNameLabel_ChunkMeta "ChunkMeta" // "17"
+#define CCNxNameLabel_Time "Time"
+#define CCNxNameLabel_Serial "Serial"
+#define CCNxNameLabel_App "App"
+
+#define CCNxNameLabelType_LabelApp(_n_) "App:" #_n_
+
+struct ccnx_name_label;
+typedef struct ccnx_name_label CCNxNameLabel;
+
+/**
+ * Parse a PARCBuffer containing a CCN LCI Name Label.
+ *
+ * When complete, the buffer's position will be set to the first byte of the value portion.
+ *
+ * @param [in] buffer A pointer to a valid PARCBuffer instance.
+ *
+ * @return NULL Memory could not be allocated
+ * @return non-NULL A pointer to a valid CCNxNameLabel instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("App:1=value");
+ * CCNxNameLabel *label = ccnxNameLabel_Parse(buffer);
+ *
+ * parcBuffer_Release(&buffer);
+ * ccnxNameLabel_Release(&label);
+ * }
+ * @endcode
+ */
+CCNxNameLabel *ccnxNameLabel_Parse(PARCBuffer *buffer);
+
+/**
+ * Create an instance of `CCNxNameLabel`.
+ *
+ * @param [in] type A CCNxNameLabelType value
+ * @param [in] parameter The value NULL or a pointer to a valid `PARCBuffer` instance.
+ *
+ * @return NULL Memory could not be allocated, or the given `CCNxNameLabelType` is one of `CCNxNameLabelType_BADNAME` or `CCNxNameLabelType_Unknown`.
+ * @return non-NULL A pointer to a valid CCNxNameLabelType instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_NAME, NULL);
+ *
+ * ccnxNameLabel_Release(&label);
+ * }
+ * @endcode
+ */
+CCNxNameLabel *ccnxNameLabel_Create(CCNxNameLabelType type, const PARCBuffer *parameter);
+
+/**
+ * Increase the number of references to a `CCNxNameLabel`.
+ *
+ * Note that new `CCNxNameLabel` is not created,
+ * only that the given `CCNxNameLabel` reference count is incremented.
+ * Discard the reference by invoking `ccnxNameLabel_Release`.
+ *
+ * @param [in] label A pointer to a `CCNxNameLabel` instance.
+ *
+ * @return The input `CCNxNameLabel` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_NAME, NULL);
+ *
+ * CCNxNameLabel *x_2 = ccnxNameLabel_Acquire(label);
+ *
+ * ccnxNameLabel_Release(&label);
+ * ccnxNameLabel_Release(&x_2);
+ * }
+ * @endcode
+ */
+CCNxNameLabel *ccnxNameLabel_Acquire(const CCNxNameLabel *label);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] labelPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_NAME, NULL);
+ *
+ * ccnxNameLabel_Release(&label);
+ * }
+ * @endcode
+ */
+void ccnxNameLabel_Release(CCNxNameLabel **labelPtr);
+
+/**
+ * Get the CCNxNameLabelType for the given `CCNxNameLabel`.
+ *
+ * @param [in] label A pointer to a valid `CCNxNameLabel` instance.
+ *
+ * @return The CCNxNameLabelType for the given `CCNxNameLabel`
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_NAME, NULL);
+ *
+ * CCNxNameLabelType type = ccnxNameLabel_GetType(label);
+ *
+ * ccnxNameLabel_Release(&label);
+ * }
+ * @endcode
+ */
+CCNxNameLabelType ccnxNameLabel_GetType(const CCNxNameLabel *label);
+
+/**
+ * Get the parameter for the given `CCNxNameLabel`.
+ *
+ * @param [in] label A pointer to a valid `CCNxNameLabel` instance.
+ *
+ * @return NULL, or a pointer to a valid `PARCBuffer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *parameter = parcBuffer_WrapCString("2");
+ * CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_APP, parameter);
+ * parcBuffer_Release(&parameter);
+ *
+ * PARCBuffer *param = ccnxNameLabel_GetParameter(label);
+ *
+ * ccnxNameLabel_Release(&label);
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxNameLabel_GetParameter(const CCNxNameLabel *label);
+
+/**
+ * Append a representation of the specified `CCNxNameLabel` instance to the given
+ * {@link PARCBufferComposer}.
+ *
+ * The representation is the canonical representation for a CCN LCI name segment.
+ *
+ * @param [in] name A pointer to a `CCNxNameLabel` instance whose representation should be appended to the @p composer.
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance to be modified.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * PARCBuffer *parameter = parcBuffer_WrapCString("2");
+ * CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_APP, parameter);
+ * parcBuffer_Release(&parameter);
+ *
+ * PARCBuffer *param = ccnxNameLabel_GetParameter(label);
+ *
+ * ccnxNameLabel_BuildString(label composer);
+ *
+ * ccnxNameLabel_Release(&label);
+ *
+ * char *string = parcBuffer_ToString(parcBufferComposer_ProduceBuffer(result));
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate(string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ *
+ * @see `CCNxNameSegment`
+ */
+PARCBufferComposer *ccnxNameLabel_BuildString(const CCNxNameLabel *label, PARCBufferComposer *composer);
+
+/**
+ * Create a copy of the specified `CCNxNameLabel` instance, producing a new, independent, instance
+ * from dynamically allocated memory.
+ *
+ * This a deep copy. All referenced memory is copied. The created instance of `CCNxNameLabel` must
+ * be released by calling {@link ccnxNameLabel_Release}().
+ *
+ * @param [in] label The `CCNxNameLabel` to copy.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new, independent copy of the given `CCNxName`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxNameLabel *original = ccnxNameLabel_Create(CCNxNameLabelType_NAME);
+ * CCNxNameLabel *copy = ccnxNameLabel_Copy(original);
+ *
+ * ...
+ *
+ * ccnxNameLabel(&original);
+ * ccnxNameLabel(&copy);
+ * }
+ * @endcode
+ */
+CCNxNameLabel *ccnxNameLabel_Copy(const CCNxNameLabel *label);
+
+/**
+ * Determine if two `CCNxNameLabel` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxNameLabel` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `ccnxNameLabel_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxNameLabel_Equals(x, y)` must return true if and only if
+ * `ccnxNameLabel_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxNameLabel_Equals(x, y)` returns true and
+ * `ccnxNameLabel_Equals(y, z)` returns true,
+ * then `ccnxNameLabel_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxNameLabel_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxNameLabel_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a `CCNxNameLabel` instance.
+ * @param [in] y A pointer to a `CCNxNameLabel` instance to be compared to @p x.
+ *
+ * @return `true` if the given `CCNxNameLabel` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxNameLabel *x = ccnxNameLabel_Create(CCNxNameLabelType_SERIAL, NULL);
+ * CCNxNameLabel *y = ccnxNameLabel_Create(CCNxNameLabelType_SERIAL, NULL);
+ *
+ * if (ccnxNameSegment_Equals(x, y)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * ccnxNameLabel_Release(&segmentA);
+ * ccnxNameLabel_Release(&segmentB);
+ * }
+ * @endcode
+ */
+bool ccnxNameLabel_Equals(const CCNxNameLabel *x, const CCNxNameLabel *y);
+
+/**
+ * Determine if an instance of `CCNxNameLabel` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] label A pointer to a `CCNxNameLabel` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+bool ccnxNameLabel_IsValid(const CCNxNameLabel *label);
+
+#ifdef Libccnx_DISABLE_VALIDATION
+# define ccnxNameLabel_OptionalAssertValid(_instance_)
+#else
+# define ccnxNameLabel_OptionalAssertValid(_instance_) ccnxNameLabel_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that an instance of `CCNxNameLabel` is valid.
+ *
+ * If the instance is not valid, terminate via `trapIllegalValue()`
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] label A pointer to a `CCNxNameLabel` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *array = parcByteArray_Allocate(64);
+ *
+ * parcBuffer_AssertValid(array);
+ * }
+ * @endcode
+ *
+ */
+void ccnxNameLabel_AssertValid(const CCNxNameLabel *label);
+#endif // libccnx_ccnx_NameType_h
diff --git a/libccnx-common/ccnx/common/ccnx_NameSegment.c b/libccnx-common/ccnx/common/ccnx_NameSegment.c
new file mode 100755
index 00000000..874da5ce
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_NameSegment.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_URI.h>
+#include <parc/algol/parc_URISegment.h>
+#include <parc/algol/parc_Varint.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Object.h>
+
+#include <ccnx/common/ccnx_NameSegment.h>
+
+struct ccnx_name_segment {
+ const CCNxNameLabel *label;
+ CCNxNameLabelType type;
+ PARCBuffer *value;
+};
+
+static bool
+_ccnxNameSegment_destructor(CCNxNameSegment **segmentP)
+{
+ assertNotNull(segmentP, "Parameter must be a non-null pointer to a CCNxNameSegment pointer.");
+
+ CCNxNameSegment *segment = *segmentP;
+ ccnxNameLabel_Release((CCNxNameLabel **) &(segment->label));
+ parcBuffer_Release(&segment->value);
+ return true;
+}
+
+parcObject_Override(CCNxNameSegment, PARCObject,
+ .destructor = (PARCObjectDestructor *) _ccnxNameSegment_destructor,
+ .copy = (PARCObjectCopy *) ccnxNameSegment_Copy,
+ .equals = (PARCObjectEquals *) ccnxNameSegment_Equals,
+ .compare = (PARCObjectCompare *) ccnxNameSegment_Compare,
+ .hashCode = (PARCObjectHashCode *) ccnxNameSegment_HashCode,
+ .toString = (PARCObjectToString *) ccnxNameSegment_ToString);
+
+parcObject_ImplementAcquire(ccnxNameSegment, CCNxNameSegment);
+
+parcObject_ImplementRelease(ccnxNameSegment, CCNxNameSegment);
+
+CCNxNameSegment *
+ccnxNameSegment_CreateLabelValue(const CCNxNameLabel *label, const PARCBuffer *value)
+{
+ CCNxNameSegment *result = parcObject_CreateInstance(CCNxNameSegment);
+ if (result != NULL) {
+ result->label = ccnxNameLabel_Acquire(label);
+ result->type = ccnxNameLabel_GetType(label);
+ result->value = parcBuffer_Acquire(value);
+ }
+ return result;
+}
+
+CCNxNameSegment *
+ccnxNameSegment_CreateTypeValue(CCNxNameLabelType type, const PARCBuffer *value)
+{
+ CCNxNameSegment *result = NULL;
+ CCNxNameLabel *label = ccnxNameLabel_Create(type, NULL);
+
+ if (label != NULL) {
+ result = ccnxNameSegment_CreateLabelValue(label, value);
+ ccnxNameLabel_Release(&label);
+ }
+ return result;
+}
+
+CCNxNameSegment *
+ccnxNameSegment_CreateTypeValueArray(CCNxNameLabelType type, size_t length, const char array[length])
+{
+ PARCBuffer *value = parcBuffer_PutArray(parcBuffer_Allocate(length), length, (const uint8_t *) array);
+ parcBuffer_Flip(value);
+
+ CCNxNameSegment *result = ccnxNameSegment_CreateTypeValue(type, value);
+ parcBuffer_Release(&value);
+
+ return result;
+}
+
+CCNxNameSegment *
+ccnxNameSegment_ParseURISegment(const PARCURISegment *uriSegment)
+{
+ CCNxNameSegment *result = NULL;
+
+ PARCBuffer *buffer = parcURISegment_GetBuffer(uriSegment);
+
+ size_t originalPosition = parcBuffer_Position(buffer);
+ CCNxNameLabel *label = ccnxNameLabel_Parse(buffer);
+
+ if (ccnxNameLabel_IsValid(label)) {
+ PARCBuffer *value = parcBuffer_Slice(buffer);
+
+ CCNxNameLabelType nameType = ccnxNameLabel_GetType(label);
+ if (nameType != CCNxNameLabelType_Unknown) {
+ result = ccnxNameSegment_CreateLabelValue(label, value);
+ }
+
+ ccnxNameLabel_Release(&label);
+ parcBuffer_Release(&value);
+
+ parcBuffer_SetPosition(buffer, originalPosition);
+ }
+
+ return result;
+}
+
+CCNxNameSegment *
+ccnxNameSegment_Copy(const CCNxNameSegment *segment)
+{
+ PARCBuffer *value = parcBuffer_Copy(segment->value);
+
+ CCNxNameLabel *label = ccnxNameLabel_Copy(segment->label);
+
+ CCNxNameSegment *result = ccnxNameSegment_CreateLabelValue(label, value);
+ ccnxNameLabel_Release(&label);
+
+ parcBuffer_Release(&value);
+ return result;
+}
+
+bool
+ccnxNameSegment_Equals(const CCNxNameSegment *segmentA, const CCNxNameSegment *segmentB)
+{
+ bool result = false;
+
+ if (segmentA == segmentB) {
+ result = true;
+ } else if (segmentA == NULL || segmentB == NULL) {
+ result = false;
+ } else {
+ if (ccnxNameLabel_Equals(segmentA->label, segmentB->label)) {
+ if (parcBuffer_Equals(ccnxNameSegment_GetValue(segmentA), ccnxNameSegment_GetValue(segmentB))) {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+int
+ccnxNameSegment_Compare(const CCNxNameSegment *segmentA, const CCNxNameSegment *segmentB)
+{
+ if (segmentA == NULL) {
+ if (segmentB == NULL) {
+ return 0;
+ }
+ return -1;
+ } else {
+ if (segmentB == NULL) {
+ return +1;
+ }
+ }
+
+ if (ccnxNameSegment_Length(segmentA) < ccnxNameSegment_Length(segmentB)) {
+ return -1;
+ }
+ if (ccnxNameSegment_Length(segmentA) > ccnxNameSegment_Length(segmentB)) {
+ return +1;
+ }
+
+ int result = parcBuffer_Compare(ccnxNameSegment_GetValue(segmentA), ccnxNameSegment_GetValue(segmentB));
+ return result;
+}
+
+CCNxNameLabelType
+ccnxNameSegment_GetType(const CCNxNameSegment *segment)
+{
+ return ccnxNameLabel_GetType(segment->label);
+}
+
+size_t
+ccnxNameSegment_Length(const CCNxNameSegment *segment)
+{
+ return parcBuffer_Remaining(segment->value);
+}
+
+PARCBuffer *
+ccnxNameSegment_GetValue(const CCNxNameSegment *segment)
+{
+ return segment->value;
+}
+
+static inline bool
+_ccnxNameSegment_IsEscapable(const char c)
+{
+ return (c == 0 || strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~", c) == NULL);
+}
+
+static inline bool
+_ccnxNameSegmentValue_IsEscaped(const PARCBuffer *value)
+{
+ bool result = false;
+
+ size_t length = parcBuffer_Remaining(value);
+
+ for (size_t i = 0; i < length; i++) {
+ if (_ccnxNameSegment_IsEscapable(parcBuffer_GetAtIndex(value, i))) {
+ result = true;
+ break;
+ }
+ }
+
+ return result;
+}
+
+PARCBufferComposer *
+ccnxNameSegment_BuildString(const CCNxNameSegment *segment, PARCBufferComposer *composer)
+{
+ // Insert the label. However, in the case of an unescaped Name value, the Name lable portion can be left off.
+
+ if (ccnxNameLabel_GetType(segment->label) != CCNxNameLabelType_NAME || _ccnxNameSegmentValue_IsEscaped(segment->value)) {
+ ccnxNameLabel_BuildString(segment->label, composer);
+ }
+
+ if (ccnxNameSegment_Length(segment) > 0) {
+ PARCURISegment *uriSegment = parcURISegment_CreateFromBuffer(ccnxNameSegment_GetValue(segment));
+ parcURISegment_BuildString(uriSegment, composer);
+
+ parcURISegment_Release(&uriSegment);
+ }
+
+ return composer;
+}
+
+PARCHashCode
+ccnxNameSegment_HashCode(const CCNxNameSegment *segment)
+{
+ PARCHash32Bits *hash = parcHash32Bits_Create();
+
+ parcHash32Bits_Update(hash, &segment->type, sizeof(segment->type));
+ if (parcBuffer_Remaining(segment->value) > 0) {
+ parcHash32Bits_UpdateUint32(hash, parcBuffer_HashCode(segment->value));
+ }
+
+ uint32_t result = parcHash32Bits_Hash(hash);
+
+ parcHash32Bits_Release(&hash);
+
+ return result;
+}
+
+char *
+ccnxNameSegment_ToString(const CCNxNameSegment *segment)
+{
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ ccnxNameSegment_BuildString(segment, composer);
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ }
+
+ return result;
+}
+
+void
+ccnxNameSegment_Display(const CCNxNameSegment *segment, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "CCNxNameSegment@%p {", segment);
+ parcDisplayIndented_PrintLine(indentation + 1, "type=%d", segment->type);
+ parcBuffer_Display(segment->value, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+void
+ccnxNameSegment_AssertValid(const CCNxNameSegment *segment)
+{
+ assertTrue(ccnxNameSegment_IsValid(segment), "CCNxNameSegment is invalid.");
+}
+
+bool
+ccnxNameSegment_IsValid(const CCNxNameSegment *segment)
+{
+ bool result = false;
+
+ if (segment != NULL) {
+ if (parcBuffer_IsValid(segment->value) == true) {
+ result = true;
+ }
+ }
+
+ return result;
+}
diff --git a/libccnx-common/ccnx/common/ccnx_NameSegment.h b/libccnx-common/ccnx/common/ccnx_NameSegment.h
new file mode 100644
index 00000000..44c1ee57
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_NameSegment.h
@@ -0,0 +1,566 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_NameSegment.h
+ * @ingroup Naming
+ * @brief A path segment of a CCNx Name
+ *
+ * An RFC3986 compliant implementation of URI segments, where each path segment carries a label.
+ * See {@link CCNxName} for more information.
+ *
+ */
+#ifndef libccnx_ccnx_NameSegment_h
+#define libccnx_ccnx_NameSegment_h
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/ccnx_NameLabel.h>
+
+#include <parc/algol/parc_URI.h>
+
+struct ccnx_name_Segment;
+/**
+ * @typedef CCNxNameSegment
+ * @brief A path segment of a `CCNxName`
+ */
+typedef struct ccnx_name_segment CCNxNameSegment;
+
+/**
+ * Create a CCNxNameSegment instance initialised with the given type and value.
+ *
+ * @param [in] type A valid CCNxNameLabelType
+ * @param [in] value A valid PARCBuffer containing the value of the name segment.
+ *
+ * @return non-NULL A pointer to a valid CCNxNameSegment instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *value = parcBuffer_WrapCString("value");
+ *
+ * CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, value);
+ *
+ * parcBuffer_Release(&value);
+ * }
+ * @endcode
+ */
+CCNxNameSegment *ccnxNameSegment_CreateTypeValue(CCNxNameLabelType type, const PARCBuffer *value);
+
+/**
+ * Create a CCNxNameSegment instance initialised with the given type and value taken from the given array of bytes.
+ *
+ * @param [in] type A valid CCNxNameLabelType
+ * @param [in] length The number of bytes in @p array.
+ * @param [in] array A pointer to a buffer containing the bytes for the value of the name segment.
+ *
+ * @return non-NULL A pointer to a valid CCNxNameSegment instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValueArray(CCNxNameLabelType_NAME, 5, "value");
+ * }
+ * @endcode
+ */
+CCNxNameSegment *ccnxNameSegment_CreateTypeValueArray(CCNxNameLabelType type, size_t length, const char *array);
+
+/**
+ * Parse a `CCNxNameSegment` from a {@link PARCURISegment} consisting of type specification and value.
+ *
+ * The name must be in conformance with `draft-mosko-icnrg-ccnxlabeledcontent-00`
+ *
+ * Names that use mnemonic values for labels, must conform to thier respective specifications.
+ * See `draft-scott-icnrg-ccnxnameregistry-00` for a list of assigned names and type values.
+ *
+ * @param [in] uriSegment A pointer to a valid `PARCURISegment`
+ * @return non-NULL A pointer to an allocated `CCNxNameSegment` which must eventually be released by calling
+ * {@link ccnxNameSegment_Release}().
+ * @return NULL An error occurred.
+ * @see `ccnxNameSegment_Release()`
+ *
+ * Example:
+ * @code
+ * {
+ * char *lciSegment = CCNxNameLabel_Name "=" "abcde";
+ * PARC_URISegment *uriSegment = parcURISegment_Parse(lciSegment, NULL);
+ *
+ * CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(uriSegment);
+ *
+ * CCNxNameLabelType type = ccnxNameSegment_GetType(actual);
+ * assertTrue(CCNxNameLabelType_NAME == type, "Expected %04x, actual %04x", 0x20, type);
+ *
+ * ccnxNameSegment_Release(&actual);
+ * parcURISegment_Release(&uriSegment);
+ * }
+ * @endcode
+ */
+CCNxNameSegment *ccnxNameSegment_ParseURISegment(const PARCURISegment *uriSegment);
+
+/**
+ * Create a new `CCNxNameSegment` by copying the given `CCNxNameSegment`. This is a deep copy,
+ * and the created instance must eventually be released by calling {@link ccnxNameSegment_Release}().
+ *
+ * @param [in] segment A `CCNxNameSegment` pointer.
+ * @return An allocated `CCNxNameSegment` which must eventually be released by calling {@link ccnxNameSegment_Release}().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *value = parcBuffer_WrapCString("hello");
+ * CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, value);
+ *
+ * CCNxNameSegment *copy = ccnxNameSegment_Copy(segment);
+ *
+ * ccnxNameSegment_Release(&segment);
+ * ccnxNameSegment_Copy(&copy);
+ * parcBuffer_Release(&value);
+ * }
+ * @endcode
+ */
+CCNxNameSegment *ccnxNameSegment_Copy(const CCNxNameSegment *segment);
+
+/**
+ * Determine if two `CCNxNameSegment` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxNameSegment` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `ccnxNameSegment_Equal(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxNameSegment_Equal(x, y)` must return true if and only if
+ * `ccnxNameSegment_Equal(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxNameSegment_Equal(x, y)` returns true and
+ * `ccnxNameSegment_Equal(y, z)` returns true,
+ * then `ccnxNameSegment_Equal(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxNameSegment_Equal(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxNameSegment_Equal(x, NULL)` must return false.
+ *
+ * @param [in] segmentA A pointer to a `CCNxNameSegment` instance.
+ * @param [in] segmentB A pointer to a `CCNxNameSegment` instance to be compared to `segmentA`.
+ *
+ * @return `true` if the given `CCNxNameSegment` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * char *lciSegment = CCNxNameLabelType_Label_Chunk "=" "123";
+ * PARC_URISegment *uriSegment = parcURISegment_Parse(lciSegment, NULL);
+ * CCNxNameSegment *segmentA = ccnxNameSegment_ParseURISegment(uriSegment);
+ *
+ * PARCBuffer *buf = parcBuffer_WrapCString("123");
+ * CCNxNameSegment *segmentB = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_CHUNK, buf);
+ *
+ * if (ccnxNameSegment_Equals(expected, actual)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * ccnxNameSegment_Release(&segmentA);
+ * ccnxNameSegment_Release(&segmentB);
+ * parcURISegment_Release(&uriSegment);
+ * parcBuffer_Release(&buf);
+ * }
+ * @endcode
+ */
+bool ccnxNameSegment_Equals(const CCNxNameSegment *segmentA, const CCNxNameSegment *segmentB);
+
+/**
+ * A signum function comparing two `CCNxNameSegment` instances.
+ *
+ * Used to determine the ordering relationship of two `CCNxNameSegment` instances.
+ *
+ * @param [in] segmentA A pointer to a `CCNxNameSegment` instance.
+ * @param [in] segmentB A pointer to a `CCNxNameSegment` instance to be compared to `segmentA`.
+ *
+ * @return 0 if `segmentA` and `segmentB` are equivalent
+ * @return < 0 if `segmentA` < `segmentB`
+ * @return > 0 if `segmentA` > `segmentB`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *valueA = parcBuffer_WrapCString("apple");
+ * CCNxNameSegment *segmentA = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, valueA);
+ *
+ * PARCBuffer *valueB = parcBuffer_WrapCString("banana");
+ * CCNxNameSegment *segmentB = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, valueB);
+ *
+ * int signum = ccnxNameSegment_Compare(segmentA, segmentB);
+ *
+ * ccnxNameSegment_Release(&segmentA);
+ * parcBuffer_Release(&bufA);
+ * ccnxNameSegment_Release(&segmentB);
+ * parcBuffer_Release(&bufB);
+ * }
+ * @endcode
+ */
+int ccnxNameSegment_Compare(const CCNxNameSegment *segmentA, const CCNxNameSegment *segmentB);
+
+/**
+ * Get a pointer to the underlying PARCBuffer storing the value of the given `CCNxNameSegment`.
+ *
+ * A new reference to the instance is not created.
+ * If the caller requires a reference to live beyond the lifetime of the `CCNxNameSegment`
+ * it must acquire a reference via {@link parcBuffer_Acquire}.
+ *
+ * Any modifications to the buffer's position, limit or mark will affect subsequent use of the buffer.
+ *
+ * @param [in] segment A pointer to a `CCNxNameSegment` instance.
+ * @return A pointer to the underlying @link PARCBuffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARC_URISegment *uriSegment = parcURISegment_Parse("label:param=value");
+ *
+ * CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(uriSegment);
+ *
+ * PARCBuffer *value = ccnxNameSegment_GetValue(actual);
+ *
+ * ccnxNameSegment_Release(&actual);
+ * parcURISegment_Release(&uriSegment);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxNameSegment_Length}()
+ */
+PARCBuffer *ccnxNameSegment_GetValue(const CCNxNameSegment *segment);
+
+/**
+ * Get a pointer to the underlying PARCBuffer storing the parameter of the given `CCNxNameSegment`.
+ *
+ * A new reference to the instance is not created.
+ * If the caller requires a reference to live beyond the lifetime of the `CCNxNameSegment`
+ * it must acquire a reference via {@link parcBuffer_Acquire}.
+ *
+ * Any modifications to the buffer's position, limit or mark will affect subsequent use of the buffer.
+ *
+ * @param [in] segment A pointer to a `CCNxNameSegment` instance.
+ * @return NULL The given `CCNxNameSegment` does not specify a parameter value.
+ * @return non-NULL A pointer to the underlying `PARCBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxNameSegment *segment = ccnxNameSegment_ParseURISegment("label:param=value");
+ *
+ * PARCBuffer *parameter = ccnxNameSegment_GetParameter(segment);
+ *
+ * ccnxNameSegment_Release(&segment);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxNameSegment_Length}()
+ */
+PARCBuffer *ccnxNameSegment_GetParameter(const CCNxNameSegment *segment);
+
+/**
+ * Produce a nul-terminated C string representation of the given `CCNxNameSegment`.
+ *
+ * A string representation, such as "1=foo".
+ *
+ * @param [in] segment A CCNxNameSegment pointer.
+ * @return An allocated null-terminated byte array that must be deallocated by `{@link parcMemory_Deallocate}()`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/212");
+ * CCNxNameSegment *segment = ccnxName_GetSegment(name, 3);
+ *
+ * char *string = ccnxNameSegment_ToString(segment);
+ * printf("Hello: %s\n", string);
+ *
+ * parcMemory_Deallocate(string);
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ *
+ * @see `parcMemory_Deallocate`
+ */
+char *ccnxNameSegment_ToString(const CCNxNameSegment *segment);
+
+/**
+ * Print a human readable representation of the given `CCNxNameSegment`.
+ *
+ * @param [in] segment A pointer to the instance to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/radiation/212");
+ * CCNxNameSegment *segment = ccnxName_GetSegment(name, 3);
+ *
+ * ccnxNameSegment_Display(segment, 0);
+ *
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ *
+ */
+void ccnxNameSegment_Display(const CCNxNameSegment *segment, int indentation);
+
+/**
+ * Append a printable-character representation of the specified instance to the given {@link PARCBufferComposer}.
+ *
+ * @param [in] segment A pointer to the `CCNxNameSegment` instance.
+ * @param [in,out] composer A pointer to the `PARCBufferComposer` instance onto which to append our printable representation.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * ccnxNameSegment_BuildString(instance, result);
+ *
+ * char *string = parcBuffer_ToString(parcBufferComposer_ProduceBuffer(result));
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate(string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ *
+ * @see PARCBufferComposer
+ */
+PARCBufferComposer *ccnxNameSegment_BuildString(const CCNxNameSegment *segment, PARCBufferComposer *composer);
+
+/**
+ * Return the length of the specified `CCNxNameSegment`, in bytes.
+ *
+ * @param [in] segment A pointer to a `CCNxNameSegment` instance.
+ * @return The number of bytes for the value of the given `CCNxNameSegment`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/sensors/humidity/12");
+ * CCNxNameSegment *segment = ccnxName_GetSegment(name, 3);
+ *
+ * int length = ccnxNameSegment_Length(segment);
+ *
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ */
+size_t ccnxNameSegment_Length(const CCNxNameSegment *segment);
+
+/**
+ * Get the label of the given `CCNxNameSegment`.
+ *
+ * @param [in] segment A pointer to a `CCNxNameSegment` instance.
+ * @return non-NULL A pointer to a PARCBuffer instance containing the label.
+ * @return NULL The CCNxNameSegment instance does not have a label.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buf = parcBuffer_WrapCString("apple");
+ * CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf);
+ *
+ * CCNxNameLabelType type = ccnxNameSegment_GetType(segment);
+ *
+ * ccnxNameSegment_Release(&segment);
+ * parcBuffer_Release(&buf);
+ * }
+ * @endcode
+ *
+ * @see `CCNxNameLabelType`
+ */
+PARCBuffer *ccnxNameSegment_GetLabel(const CCNxNameSegment *segment);
+
+/**
+ * Get the {@link CCNxNameLabelType} of the given `CCNxNameSegment`.
+ *
+ * @param [in] segment A pointer to a `CCNxNameSegment` instance.
+ * @return The `CCNxNameLabelType` of the specified `CCNxNameSegment` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buf = parcBuffer_WrapCString("apple");
+ * CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf);
+ *
+ * CCNxNameLabelType type = ccnxNameSegment_GetType(segment);
+ *
+ * ccnxNameSegment_Release(&segment);
+ * parcBuffer_Release(&buf);
+ * }
+ * @endcode
+ *
+ * @see `CCNxNameLabelType`
+ */
+CCNxNameLabelType ccnxNameSegment_GetType(const CCNxNameSegment *segment);
+
+/**
+ * Return a hashcode for the given `CCNxNameSegment`.
+ *
+ * Whenever `HashCode()` is invoked on the same instance more than once within the same execution environment,
+ * the HashCode function must consistently return the same value, provided no information used in its corresponding
+ * `Equals()` comparisons on the same instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ *
+ * If two instances are equal according to the `Equals()` function,
+ * then calling the `HashCode` function on each of the two objects must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the `Equals()` function,
+ * then calling the HashCode() method on each of the two instances must produce distinct integer results.
+ * However, the programmer should be aware that producing distinct results for unequal instances
+ * may improve the performance of some data structures.
+ *
+ * @param segment A pointer to a `CCNxNameSegment` instance.
+ * @return An unsigned 32-bit integer hash code value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *bufA =parcBuffer_WrapCString("Test");
+ *
+ * CCNxNameSegment *segmentA = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufA);
+ *
+ * uint32_t hashCode = ccnxNameSegment_HashCode(segmentA);
+ *
+ * ccnxNameSegment_Release(&segmentA);
+ * parcBuffer_Release(&bufA);
+ * }
+ * @endcode
+ *
+ * @see `parcHash32Bits_Hash`
+ */
+PARCHashCode ccnxNameSegment_HashCode(const CCNxNameSegment *segment);
+
+/**
+ * Increase the number of references to a `CCNxNameSegment`.
+ *
+ * Note that a new `CCNxNameSegment` is not created,
+ * only that the given `CCNxNameSegment` reference count is incremented.
+ * Discard the reference by invoking {@link ccnxNameSegment_Release}().
+ *
+ * @param [in] segment A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxNameSegment *segment = ccnxNameSegment_Acquire(instance);
+ *
+ * ccnxNameSegment_Release(&segment);
+ *
+ * }
+ * @endcode
+ *
+ * @see ccnxNameSegment_Release
+ */
+CCNxNameSegment *ccnxNameSegment_Acquire(const CCNxNameSegment *segment);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] segmentP A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxNameSegment *segment = ccnxNameSegment_Acquire(instance);
+ *
+ * ccnxNameSegment_Release(&segment);
+ *
+ * }
+ * @endcode
+ *
+ * @see ccnxNameSegment_Acquire
+ */
+void ccnxNameSegment_Release(CCNxNameSegment **segmentP);
+
+#ifdef Libccnx_DISABLE_VALIDATION
+# define ccnxNameSegment_OptionalAssertValid(_instance_)
+#else
+# define ccnxNameSegment_OptionalAssertValid(_instance_) ccnxNameSegment_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that an instance of `CCNxNameSegment` is valid.
+ *
+ * If the instance is not valid, terminate via {@link trapIllegalValue}
+ *
+ * Valid means the internal state of the type is consistent with its
+ * required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] segment A pointer to the instance to check.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * ccnxNameSegment_AssertValid(segment);
+ *
+ * }
+ * @endcode
+ */
+void ccnxNameSegment_AssertValid(const CCNxNameSegment *segment);
+
+/**
+ * Determine if an instance of `CCNxNameSegment` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its
+ * required current or future behaviour.
+ * This may include the validation of internal instances of referenced objects.
+ *
+ * @param [in] segment A pointer to the instance to check.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * ccnxNameSegment_IsValid(segment);
+ *
+ * }
+ * @endcode
+ */
+bool ccnxNameSegment_IsValid(const CCNxNameSegment *segment);
+#endif // libccnx_ccnx_NameSegment_h
diff --git a/libccnx-common/ccnx/common/ccnx_NameSegmentNumber.c b/libccnx-common/ccnx/common/ccnx_NameSegmentNumber.c
new file mode 100755
index 00000000..b7187158
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_NameSegmentNumber.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/ccnx_NameSegmentNumber.h>
+#include <ccnx/common/ccnx_NameSegment.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+bool
+ccnxNameSegmentNumber_IsValid(const CCNxNameSegment *nameSegment)
+{
+ bool result = false;
+
+ size_t remaining = parcBuffer_Remaining(ccnxNameSegment_GetValue(nameSegment));
+ if (remaining > 0 && remaining < 8) {
+ result = true;
+ }
+
+ return result;
+}
+
+void
+ccnxNameSegmentNumber_AssertValid(const CCNxNameSegment *nameSegment)
+{
+ assertTrue(ccnxNameSegmentNumber_IsValid(nameSegment), "Encountered an invalid CCNxNameSegment");
+}
+
+CCNxNameSegment *
+ccnxNameSegmentNumber_Create(CCNxNameLabelType type, uint64_t value)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ bool mustContinue = false;
+ for (int byte = 7; byte >= 0; byte--) {
+ uint8_t b = (value >> (byte * 8)) & 0xFF;
+ if (b != 0 || byte == 0 || mustContinue) {
+ parcBufferComposer_PutUint8(composer, b);
+ mustContinue = true;
+ }
+ }
+ PARCBuffer *buffer = parcBuffer_Flip(parcBufferComposer_GetBuffer(composer));
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(type, buffer);
+ parcBufferComposer_Release(&composer);
+
+ return segment;
+}
+
+uint64_t
+ccnxNameSegmentNumber_Value(const CCNxNameSegment *nameSegment)
+{
+ const PARCBuffer *buffer = ccnxNameSegment_GetValue(nameSegment);
+
+ uint64_t result = 0;
+
+ for (size_t i = 0; i < parcBuffer_Remaining(buffer); i++) {
+ result = (result << 8) | parcBuffer_GetAtIndex(buffer, i);
+ }
+ return result;
+}
diff --git a/libccnx-common/ccnx/common/ccnx_NameSegmentNumber.h b/libccnx-common/ccnx/common/ccnx_NameSegmentNumber.h
new file mode 100755
index 00000000..a685c713
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_NameSegmentNumber.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_NameSegmentNumber.h
+ * @ingroup Naming
+ * @brief Utilities for creating and parsing CCNxNameSegments that contain an integer value.
+ *
+ * CCNxNameSegments may optionally contain an integer value. This file contains some utilities
+ * for creating and parsing CCNxNameSegments with integer values.
+ * See {@link CCNxNameSegment}, {@link CCNxNameLabelType}, and {@link CCNxName} for more information.
+ *
+ */
+#ifndef libccnx_ccnx_NameSegmentNumber_h
+#define libccnx_ccnx_NameSegmentNumber_h
+
+#include <stdbool.h>
+
+#include <ccnx/common/ccnx_NameSegment.h>
+#include <ccnx/common/ccnx_NameLabel.h>
+
+/**
+ * Create a new {@link CCNxNameSegment} consisting of a type and integer value.
+ *
+ * The newly created instance must eventually be released by calling {@link ccnxNameSegment_Release}().
+ *
+ * @param [in] type A valid {@link CCNxNameLabelType}.
+ * @param [in] value The integer value to assign to the `CCNxNameSegment`.
+ * @return A pointer to a new `CCNxNameSegment` instance, consisting of a type and integer value.
+ *
+ * Example:
+ * @code
+ * {
+ * uint64_t expected = 0x123456789ABCDEF0;
+ * CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+ *
+ * uint64_t actual = ccnxNameSegmentNumber_Value(segment);
+ *
+ * assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual);
+ *
+ * ccnxNameSegment_Release(&segment);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxNameSegment_Release}
+ * @see `CCNxNameLabelType`
+ */
+CCNxNameSegment *ccnxNameSegmentNumber_Create(CCNxNameLabelType type, uint64_t value);
+
+/**
+ * Decode an integer value from a {@link CCNxNameSegment}.
+ *
+ * Given a `CCNxNameSegment` with a numeric type, return the integer value associated with the `CCNxNameSegment`.
+ *
+ * @param [in] nameSegment A pointer a `CCNxNameSegment` instance containing an integer value.
+ * @return The integer value of the `CCNxNameSegment`.
+ *
+ * Example:
+ * @code
+ * {
+ * uint64_t expected = 0x123456789ABCDEF0;
+ * CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+ *
+ * uint64_t actual = ccnxNameSegmentNumber_Value(segment);
+ *
+ * assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual);
+ *
+ * ccnxNameSegment_Release(&segment);
+ * }
+ * @endcode
+ */
+uint64_t ccnxNameSegmentNumber_Value(const CCNxNameSegment *nameSegment);
+
+/**
+ * Determine if the given CCNxNameSegment value represents a valid encoded number.
+ *
+ * A valid encoded number contains at least 1 byte and nor more than 8 bytes.
+ *
+ * @param [in] nameSegment A pointer to a CCNxNameSegment instance.
+ *
+ * Example:
+ * @code
+ * {
+ * uint64_t expected = 0x123456789ABCDEF0;
+ * CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+ *
+ * ccnxNameSegmentNumber_AssertValid(segment);
+ * }
+ * @endcode
+ */
+bool ccnxNameSegmentNumber_IsValid(const CCNxNameSegment *nameSegment);
+
+/**
+ * Assert that the given CCNxNameSegment value represents a valid encoded number.
+ *
+ * @param [in] nameSegment A pointer to a CCNxNameSegment instance.
+ *
+ * Example:
+ * @code
+ * {
+ * uint64_t expected = 0x123456789ABCDEF0;
+ * CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+ *
+ * ccnxNameSegmentNumber_AssertValid(segment);
+ * }
+ * @endcode
+ */
+void ccnxNameSegmentNumber_AssertValid(const CCNxNameSegment *nameSegment);
+#endif // libccnx_ccnx_NameSegmentNumber_h
diff --git a/libccnx-common/ccnx/common/ccnx_PayloadType.h b/libccnx-common/ccnx/common/ccnx_PayloadType.h
new file mode 100755
index 00000000..de75592e
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_PayloadType.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_PayloadType.h
+ * @brief An enumeration for the supported types of a content object payload.
+ *
+ * @see CCNxContentObject
+ *
+ */
+
+#ifndef libccnx_ccnx_PayloadType_h
+#define libccnx_ccnx_PayloadType_h
+
+/**
+ * @typedef CCNxPayloadType
+ * @brief Specifies how the Payload should be interpreted.
+ */
+typedef enum ccnx_payload_type {
+ CCNxPayloadType_DATA = 0,
+ CCNxPayloadType_KEY = 1,
+ CCNxPayloadType_LINK = 2,
+ CCNxPayloadType_MANIFEST = 3
+} CCNxPayloadType;
+#endif /* defined(libccnx_ccnx_PayloadType_h) */
diff --git a/libccnx-common/ccnx/common/ccnx_TimeStamp.c b/libccnx-common/ccnx/common/ccnx_TimeStamp.c
new file mode 100755
index 00000000..75add669
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_TimeStamp.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Object.h>
+
+#include <ccnx/common/ccnx_TimeStamp.h>
+
+#include <parc/algol/parc_Memory.h>
+
+struct ccnx_timestamp {
+ struct timespec timespec;
+};
+
+static void
+_Destroy(CCNxTimeStamp **timeStampPtr)
+{
+}
+
+parcObject_ExtendPARCObject(CCNxTimeStamp, _Destroy, ccnxTimeStamp_Copy,
+ ccnxTimeStamp_ToString, ccnxTimeStamp_Equals, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(ccnxTimeStamp, CCNxTimeStamp);
+
+parcObject_ImplementRelease(ccnxTimeStamp, CCNxTimeStamp);
+
+void
+ccnxTimeStamp_AssertValid(const CCNxTimeStamp *timeStamp)
+{
+ assertNotNull(timeStamp, "Parameter must be a pointer to a CCNxTimeStamp structure.");
+}
+
+CCNxTimeStamp *
+ccnxTimeStamp_CreateFromCurrentUTCTime(void)
+{
+ struct timeval timeval;
+ gettimeofday(&timeval, NULL);
+
+ struct timespec timespec;
+ timespec.tv_sec = timeval.tv_sec;
+ timespec.tv_nsec = timeval.tv_usec * 1000;
+
+ return ccnxTimeStamp_CreateFromTimespec(&timespec);
+}
+
+CCNxTimeStamp *
+ccnxTimeStamp_CreateFromTimespec(const struct timespec *timespec)
+{
+ CCNxTimeStamp *result = parcObject_CreateInstance(CCNxTimeStamp);
+ result->timespec.tv_sec = timespec->tv_sec;
+ result->timespec.tv_nsec = timespec->tv_nsec;
+
+ return result;
+}
+
+struct timespec
+ccnxTimeStamp_AsTimespec(const CCNxTimeStamp *timeStamp)
+{
+ ccnxTimeStamp_AssertValid(timeStamp);
+ return timeStamp->timespec;
+}
+
+CCNxTimeStamp *
+ccnxTimeStamp_CreateFromNanosecondsSinceEpoch(uint64_t nanos)
+{
+ struct timespec timespec = { .tv_sec = nanos / 1000000000, .tv_nsec = (nanos % 1000000000) };
+
+ return ccnxTimeStamp_CreateFromTimespec(&timespec);
+}
+
+CCNxTimeStamp *
+ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(uint64_t millis)
+{
+ struct timespec timespec = { .tv_sec = millis / 1000, .tv_nsec = (millis % 1000) * 1000000 };
+ return ccnxTimeStamp_CreateFromTimespec(&timespec);
+}
+
+bool
+ccnxTimeStamp_Equals(const CCNxTimeStamp *timeStampA, const CCNxTimeStamp *timeStampB)
+{
+ if (timeStampA == timeStampB) {
+ return true;
+ }
+ if (timeStampA == NULL || timeStampB == NULL) {
+ return false;
+ }
+ if (timeStampA->timespec.tv_sec == timeStampB->timespec.tv_sec) {
+ if (timeStampA->timespec.tv_nsec == timeStampB->timespec.tv_nsec) {
+ return true;
+ }
+ }
+ return false;
+}
+
+uint64_t
+ccnxTimeStamp_AsNanoSeconds(const CCNxTimeStamp *timeStamp)
+{
+ ccnxTimeStamp_AssertValid(timeStamp);
+ uint64_t result = timeStamp->timespec.tv_sec * 1000000000ULL + timeStamp->timespec.tv_nsec;
+ return result;
+}
+
+char *
+ccnxTimeStamp_ToString(const CCNxTimeStamp *timeStamp)
+{
+ if (timeStamp == NULL) {
+ return parcMemory_StringDuplicate("NULL", 4);
+ }
+
+ char *string;
+ int failure = asprintf(&string, "%ld.%ld", timeStamp->timespec.tv_sec, timeStamp->timespec.tv_nsec);
+ assertTrue(failure > -1, "Error asprintf");
+
+ char *result = parcMemory_StringDuplicate(string, strlen(string));
+ free(string);
+ return result;
+}
+
+CCNxTimeStamp *
+ccnxTimeStamp_Copy(const CCNxTimeStamp *timeStamp)
+{
+ ccnxTimeStamp_AssertValid(timeStamp);
+ return ccnxTimeStamp_CreateFromTimespec(&timeStamp->timespec);
+}
diff --git a/libccnx-common/ccnx/common/ccnx_TimeStamp.h b/libccnx-common/ccnx/common/ccnx_TimeStamp.h
new file mode 100755
index 00000000..e21f5a4e
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_TimeStamp.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_TimeStamp.h
+ * @brief A CCNxTimeStamp represents a point in time.
+ *
+ */
+#ifndef libccnx_ccnx_TimeStamp_h
+#define libccnx_ccnx_TimeStamp_h
+
+#include <sys/time.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+struct ccnx_timestamp;
+/**
+ * @typedef CCNxTimeStamp
+ * @brief A CCNxTimeStamp represents a point in time.
+ */
+typedef struct ccnx_timestamp CCNxTimeStamp;
+
+/**
+ * Assert that a pointer to a `CCNxTimeStamp` instance and the instance itself is valid.
+ *
+ * @param [in] timeStamp A pointer to a CCNxTimeStamp intance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTimeStamp *timestamp = ccnxTimeStamp_CreateFromCurrentUTCTime();
+ * ccnxTimeStamp_AssertValid(timestamp);
+ * ccnxTimeStamp_Release(&timestamp);
+ * }
+ * @endcode
+ *
+ */
+void ccnxTimeStamp_AssertValid(const CCNxTimeStamp *timeStamp);
+
+/**
+ * Create a new `CCNxTimeStamp` instance from the current local time.
+ *
+ * The newly created instance must eventually be released by calling {@link ccnxTimeStamp_Release}();
+ *
+ * @return An instance of a `CCNxTimeStamp` initialized to the current local time.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTimeStamp *timestamp = ccnxTimeStamp_CreateFromCurrentUTCTime();
+ * ccnxTimeStamp_AssertValid(timestamp);
+ * ccnxTimeStamp_Release(&timestamp);
+ * }
+ * @endcode
+ *
+ * @see ccnxTimeStamp_Release
+ */
+CCNxTimeStamp *ccnxTimeStamp_CreateFromCurrentUTCTime(void);
+
+/**
+ * Create a new `CCNxTimeStamp` instance from the given `struct timespec`.
+ *
+ * Given a `struct timespec` create a `CCNxTimeStamp` representing the same time.
+ * The newly created instance must eventually be released by calling {@link ccnxTimeStamp_Release}();
+ *
+ * @param [in] timespec The `struct timespec` of the time to represent.
+ * @return An instance of a `CCNxTimeStamp` initialized from the specified `struct timespec`.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timespec time = {.tv_sec = 1, .tv_nsec = 1 };
+ *
+ * CCNxTimeStamp *timestamp = ccnxTimeStamp_CreateFromTimespec(&time);
+ *
+ * ccnxTimeStamp_Release(&timestamp);
+ * }
+ * @endcode
+ *
+ * @see ccnxTimeStamp_Release
+ */
+CCNxTimeStamp *ccnxTimeStamp_CreateFromTimespec(const struct timespec *timespec);
+
+/**
+ * Return a `struct timespec` representation of the given `CCNxTimeStamp`.
+ *
+ * The internal form of the `CCNxTimeStamp` is returned as a `struct timespec`.
+ *
+ * @param [in] timeStamp A pointer to a `CCNxTimeStamp` instance.
+ * @return A `struct timespec` representation of the given `CCNxTimeStamp`.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timespec time = {.tv_sec = 1, .tv_nsec = 1 };
+ *
+ * CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromTimespec(&time);
+ *
+ * struct timespec actualTime = ccnxTimeStamp_AsTimespec(timeStamp);
+ * assertTrue(time.tv_sec == actualTime.tv_sec && time.tv_nsec == actualTime.tv_nsec, "Expected timespec to be equal.");
+ *
+ * ccnxTimeStamp_Release(&timeStamp);
+ * }
+ * @endcode
+ */
+struct timespec ccnxTimestamp_AsTimespec(const CCNxTimeStamp *timeStamp);
+
+/**
+ * Create a new `CCNxTimeStamp` instance initialized to the given number of milliseconds from the epoch.
+ *
+ * The epoch is defined as 00:00:00, 01/01/1970.
+ * The newly created instance must eventually be released by calling {@link ccnxTimeStamp_Release}();
+ *
+ * @param [in] milliseconds A `uint64_t` specifying the number of milliseconds since the epoch.
+ * @return A pointer to a `CCNxTimeStamp` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTimeStamp *timestamp = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(100);
+ * ccnxTimeStamp_AssertValid(timestamp);
+ * ccnxTimeStamp_Release(&timestamp);
+ * }
+ * @endcode
+ *
+ * @see ccnxTimeStamp_Release
+ */
+extern CCNxTimeStamp *ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(uint64_t milliseconds);
+
+/**
+ * Create a new `CCNxTimeStamp` instance initialized to the given number of nanoseconds from the epoch.
+ *
+ * The epoch is defined as 00:00:00, 01/01/1970.
+ * The newly created instance must eventually be released by calling {@link ccnxTimeStamp_Release}();
+ *
+ * @param [in] nanoseconds A uint64_t specifying the number of nanoseconds since the epoch.
+ * @return A pointer to a `CCNxTimeStamp` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTimeStamp *timestamp = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(100);
+ * ccnxTimeStamp_AssertValid(timestamp);
+ * ccnxTimeStamp_Release(&timestamp);
+ * }
+ * @endcode
+ *
+ * @see ccnxTimeStamp_Release
+ */
+CCNxTimeStamp *ccnxTimeStamp_CreateFromNanosecondsSinceEpoch(uint64_t nanoseconds);
+
+/**
+ * Return the value of the given `CCNxTimeStamp` as an unsigned 64-bit integer representing the number of nanoseconds since the epoch.
+ *
+ * The resolution of a `CCNxTimeStamp` is nanoseconds, although the resolution of the host environment may not.
+ *
+ * @param [in] timeStamp A pointer to a `CCNxTimeStamp` instance.
+ * @return The value of the given `CCNxTimeStamp` as an unsigned 64-bit integer
+ *
+ * Example:
+ * @code
+ * {
+ * uint64_t expected = 1099511627776ULL;
+ *
+ * CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromNanosecondsSinceEpoch(expected);
+ *
+ * uint64_t actual = ccnxTimeStamp_AsNanoSeconds(timeStamp);
+ *
+ * assertTrue(expected == actual, "Expected " PRIu64 " actual " PRIu64, expected, actual);
+ *
+ * ccnxTimeStamp_Release(&timeStamp);
+ * }
+ * @endcode
+ */
+uint64_t ccnxTimeStamp_AsNanoSeconds(const CCNxTimeStamp *timeStamp);
+
+/**
+ * Create a deep copy of the given `CCNxTimeStamp`, using dynamically allocated memory.
+ *
+ * The newly created instance must eventually be released by calling {@link ccnxTimeStamp_Release}();
+ *
+ * @param [in] timeStamp A pointer to a `CCNxTimeStamp` instance.
+ * @return A new copy of the given `CCNxTimeStamp`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(100);
+ * CCNxTimeStamp *copy = ccnxTimeStamp_Copy(timeStamp);
+ *
+ * ccnxTimeStamp_AssertValid(timeStamp);
+ * ccnxTimeStamp_AssertValid(copy);
+ *
+ * ccnxTimeStamp_Release(&timeStamp);
+ * ccnxTimeStamp_Release(&copy);
+ * }
+ * @endcode
+ *
+ * @see ccnxTimeStamp_Release
+ */
+extern CCNxTimeStamp *ccnxTimeStamp_Copy(const CCNxTimeStamp *timeStamp);
+
+/**
+ * Determine if two `CCNxTimeStamp` instances are equal.
+ *
+ *
+ * The following equivalence relations on non-null `CCNxTimeStamp` instances are maintained: *
+ * It is reflexive: for any non-null reference value `ccnxTimeStamp_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxTimeStamp_Equals(x, y)` must return true if and only if
+ * `ccnxTimeStamp_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxTimeStamp_Equals(x, y)` returns true and
+ * `ccnxTimeStamp_Equals(y, z)` returns true,
+ * then `ccnxTimeStamp_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxTimeStamp_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxTimeStamp_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] timeStampA A pointer to a `CCNxTimeStamp` instance.
+ * @param [in] timeStampB A pointer to a `CCNxTimeStamp` instance.
+ * @return `true` if the referenced CCNxTimeStamp instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTimeStamp *timeStampA = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(100);
+ * CCNxTimeStamp *timeStampB = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(100);
+ *
+ * if (ccnxTimeStamp_Equals(timeStampA, timeStampB)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ *
+ * ccnxTimeStamp_Release(&timeStampA);
+ * ccnxTimeStamp_Release(&timeStampB);
+ * }
+ * @endcode
+ */
+bool ccnxTimeStamp_Equals(const CCNxTimeStamp *timeStampA, const CCNxTimeStamp *timeStampB);
+
+/**
+ * Increase the number of references to a `CCNxTimeStamp`.
+ *
+ * Note that new `CCNxTimeStamp` is not created,
+ * only that the given `CCNxTimeStamp` reference count is incremented.
+ * Discard the reference by invoking {@link ccnxTimeStamp_Release}.
+ *
+ * @param [in] instance A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromCurrentUTCTime();
+ *
+ * CCNxTimeStamp *reference = ccnxTimeStamp_Acquire(timeStamp);
+ *
+ * ccnxTimeStamp_Release(&timeStamp);
+ * ccnxTimeStamp_Release(&reference);
+ * }
+ * @endcode
+ *
+ * @see ccnxTimeStamp_Release
+ */
+CCNxTimeStamp *ccnxTimeStamp_Acquire(const CCNxTimeStamp *instance);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] timeStampPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromCurrentUTCTime();
+ *
+ * ccnxTimeStamp_Release(&timeStamp);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxTimeStamp_Acquire}
+ */
+void ccnxTimeStamp_Release(CCNxTimeStamp **timeStampPtr);
+
+/**
+ * Produce a null-terminated C-string representation of the specified instance.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] timeStamp A pointer to a 'CCNxTimeStamp' instance.
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A nul-terminated string that must be deallocated via {@link parcMemory_Deallocate}().
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromCurrentUTCTime();
+ *
+ * char *string = ccnxTimeStamp_ToString(timeStamp);
+ *
+ * printf("Hello: %s\n", string);
+ *
+ * parcMemory_Deallocate(string);
+ * ccnxTimeStamp_Release(&timeStamp);
+ * }
+ * @endcode
+ *
+ * @see `parcMemory_Deallocate`
+ */
+char *ccnxTimeStamp_ToString(const CCNxTimeStamp *timeStamp);
+#endif // libccnx_ccnx_TimeStamp_h
diff --git a/libccnx-common/ccnx/common/ccnx_WireFormatMessage.c b/libccnx-common/ccnx/common/ccnx_WireFormatMessage.c
new file mode 100644
index 00000000..9fd82482
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_WireFormatMessage.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include "config.h"
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+
+void
+ccnxWireFormatMessage_AssertValid(const CCNxWireFormatMessage *message)
+{
+ assertNotNull(message, "Must be a non-null pointer to a CCNxWireFormatMessage.");
+
+ // Check for required fields in the underlying dictionary. Case 1036
+ CCNxWireFormatMessageInterface *impl = ccnxWireFormatMessageInterface_GetInterface(message);
+ assertNotNull(impl, "WireFormatMessage must have an valid implementation pointer.");
+ if (impl->assertValid) {
+ impl->assertValid(message);
+ }
+}
+
+static CCNxWireFormatMessage *
+_ccnxWireFormatMessage_CreateWithImpl(const CCNxWireFormatMessageInterface *impl, const PARCBuffer *wireFormatBuffer)
+{
+ CCNxWireFormatMessage *result = impl->create(wireFormatBuffer);
+ return result;
+}
+
+CCNxWireFormatMessage *
+ccnxWireFormatMessage_Create(const PARCBuffer *wireFormat)
+{
+ CCNxWireFormatMessage *result = NULL;
+
+ uint8_t version = parcBuffer_GetAtIndex(wireFormat, 0);
+ switch (version) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ result = _ccnxWireFormatMessage_CreateWithImpl(&CCNxWireFormatFacadeV1_Implementation, wireFormat);
+ break;
+ default:
+ // no action, will return NULL
+ break;
+ }
+
+ return result;
+}
+
+static CCNxWireFormatMessageInterface *
+_getImplForSchema(const CCNxTlvDictionary_SchemaVersion schemaVersion)
+{
+ CCNxWireFormatMessageInterface *result = NULL;
+ switch (schemaVersion) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ result = &CCNxWireFormatFacadeV1_Implementation;
+ break;
+ default:
+ trapIllegalValue(data->fwd_state->nextMessage.version, "Unknown schema version: %d", schemaVersion);
+ }
+ return result;
+}
+
+CCNxWireFormatMessage *
+ccnxWireFormatMessage_FromInterestPacketType(const CCNxTlvDictionary_SchemaVersion schemaVersion, const PARCBuffer *wireFormat)
+{
+ CCNxWireFormatMessageInterface *impl = _getImplForSchema(schemaVersion);
+ CCNxWireFormatMessage *result = NULL;
+
+ if (impl->fromInterestPacketType != NULL) {
+ result = impl->fromInterestPacketType(wireFormat);
+ }
+
+ return result;
+}
+
+CCNxWireFormatMessage *
+ccnxWireFormatMessage_FromInterestPacketTypeIoVec(const CCNxTlvDictionary_SchemaVersion schemaVersion, const CCNxCodecNetworkBufferIoVec *vec)
+{
+ CCNxWireFormatMessageInterface *impl = _getImplForSchema(schemaVersion);
+ CCNxWireFormatMessage *result = NULL;
+
+ if (impl->fromInterestPacketTypeIoVec != NULL) {
+ result = impl->fromInterestPacketTypeIoVec(vec);
+ }
+
+ return result;
+}
+
+CCNxWireFormatMessage *
+ccnxWireFormatMessage_FromContentObjectPacketType(const CCNxTlvDictionary_SchemaVersion schemaVersion, const PARCBuffer *wireFormat)
+{
+ CCNxWireFormatMessageInterface *impl = _getImplForSchema(schemaVersion);
+ CCNxWireFormatMessage *result = NULL;
+
+ if (impl->fromContentObjectPacketType != NULL) {
+ result = impl->fromContentObjectPacketType(wireFormat);
+ }
+
+ return result;
+}
+
+CCNxWireFormatMessage *
+ccnxWireFormatMessage_FromControlPacketType(const CCNxTlvDictionary_SchemaVersion schemaVersion, const PARCBuffer *wireFormat)
+{
+ CCNxWireFormatMessageInterface *impl = _getImplForSchema(schemaVersion);
+ CCNxWireFormatMessage *result = NULL;
+
+ if (impl->fromControlPacketType != NULL) {
+ result = impl->fromControlPacketType(wireFormat);
+ }
+
+ return result;
+}
+
+CCNxTlvDictionary *
+ccnxWireFormatMessage_GetDictionary(const CCNxWireFormatMessage *message)
+{
+ return (CCNxTlvDictionary *) message;
+}
+
+
+CCNxCodecNetworkBufferIoVec *
+ccnxWireFormatMessage_GetIoVec(const CCNxWireFormatMessage *message)
+{
+ ccnxWireFormatMessage_OptionalAssertValid(message);
+ CCNxWireFormatMessageInterface *impl = ccnxWireFormatMessageInterface_GetInterface(message);
+
+ CCNxCodecNetworkBufferIoVec *result = NULL;
+
+ if (impl->getIoVec != NULL) {
+ result = impl->getIoVec(message);
+ } else {
+ trapNotImplemented("ccnxWireFormatMessage_GetIoVec");
+ }
+
+ return result;
+}
+
+bool
+ccnxWireFormatMessage_PutIoVec(CCNxWireFormatMessage *message, CCNxCodecNetworkBufferIoVec *vec)
+{
+ ccnxWireFormatMessage_OptionalAssertValid(message);
+ CCNxWireFormatMessageInterface *impl = ccnxWireFormatMessageInterface_GetInterface(message);
+
+ bool result = false;
+
+ if (impl->putIoVec != NULL) {
+ result = impl->putIoVec(message, vec);
+ } else {
+ trapNotImplemented("ccnxWireFormatMessage_PutIoVec");
+ }
+
+ return result;
+}
+
+bool
+ccnxWireFormatMessage_PutWireFormatBuffer(CCNxWireFormatMessage *message, PARCBuffer *buffer)
+{
+ ccnxWireFormatMessage_OptionalAssertValid(message);
+ CCNxWireFormatMessageInterface *impl = ccnxWireFormatMessageInterface_GetInterface(message);
+
+ bool result = false;
+
+ if (impl->putWireFormatBuffer != NULL) {
+ result = impl->putWireFormatBuffer(message, buffer);
+ } else {
+ trapNotImplemented("ccnxWireFormatMessage_PutWireFormatBuffer");
+ }
+
+ return result;
+}
+
+PARCBuffer *
+ccnxWireFormatMessage_GetWireFormatBuffer(const CCNxWireFormatMessage *message)
+{
+ ccnxWireFormatMessage_OptionalAssertValid(message);
+ CCNxWireFormatMessageInterface *impl = ccnxWireFormatMessageInterface_GetInterface(message);
+
+ PARCBuffer *result = NULL;
+
+ if (impl->getWireFormatBuffer != NULL) {
+ result = impl->getWireFormatBuffer(message);
+ } else {
+ trapNotImplemented("ccnxWireFormatMessage_GetWireFormatBuffer");
+ }
+
+ return result;
+}
+
+void
+ccnxWireFormatMessage_WriteToFile(const CCNxWireFormatMessage *message, const char *filename)
+{
+ ccnxWireFormatMessage_OptionalAssertValid(message);
+ CCNxWireFormatMessageInterface *impl = ccnxWireFormatMessageInterface_GetInterface(message);
+
+ if (impl->writeToFile != NULL) {
+ impl->writeToFile(message, filename);
+ } else {
+ trapNotImplemented("ccnxWireFormatMessage_WriteToFile");
+ }
+}
+
+bool
+ccnxWireFormatMessage_SetProtectedRegionStart(CCNxWireFormatMessage *message, size_t startPosition)
+{
+ ccnxWireFormatMessage_OptionalAssertValid(message);
+ CCNxWireFormatMessageInterface *impl = ccnxWireFormatMessageInterface_GetInterface(message);
+
+ bool result = false;
+
+ if (impl->setProtectedRegionStart != NULL) {
+ result = impl->setProtectedRegionStart(message, startPosition);
+ } else {
+ trapNotImplemented("ccnxWireFormatMessage_SetProtectedRegionStart");
+ }
+
+ return result;
+}
+
+bool
+ccnxWireFormatMessage_SetProtectedRegionLength(CCNxWireFormatMessage *message, size_t length)
+{
+ ccnxWireFormatMessage_OptionalAssertValid(message);
+ CCNxWireFormatMessageInterface *impl = ccnxWireFormatMessageInterface_GetInterface(message);
+
+ bool result = false;
+
+ if (impl->setProtectedRegionLength != NULL) {
+ result = impl->setProtectedRegionLength(message, length);
+ } else {
+ trapNotImplemented("ccnxWireFormatMessage_SetProtectedRegionLength");
+ }
+
+ return result;
+}
+
+
+PARCCryptoHash *
+ccnxWireFormatMessage_HashProtectedRegion(const CCNxWireFormatMessage *message, PARCCryptoHasher *hasher)
+{
+ ccnxWireFormatMessage_OptionalAssertValid(message);
+ CCNxWireFormatMessageInterface *impl = ccnxWireFormatMessageInterface_GetInterface(message);
+
+ PARCCryptoHash *result = NULL;
+
+ if (impl->hashProtectedRegion != NULL) {
+ result = impl->hashProtectedRegion(message, hasher);
+ } else {
+ trapNotImplemented("ccnxWireFormatMessage_HashProtectedRegion");
+ }
+
+ return result;
+}
+
+PARCCryptoHash *
+ccnxWireFormatMessage_CreateContentObjectHash(CCNxWireFormatMessage *message)
+{
+ ccnxWireFormatMessage_AssertValid(message);
+ CCNxWireFormatMessageInterface *impl = ccnxWireFormatMessageInterface_GetInterface(message);
+
+ PARCCryptoHash *result = NULL;
+
+ if (impl->computeContentObjectHash != NULL) {
+ result = impl->computeContentObjectHash(message);
+ } else {
+ trapNotImplemented("ccnxWireFormatMessage_ComputeContentObjectHash");
+ }
+
+ return result;
+}
+
+CCNxWireFormatMessage *
+ccnxWireFormatMessage_Acquire(const CCNxWireFormatMessage *message)
+{
+ return ccnxTlvDictionary_Acquire(message);
+}
+
+void
+ccnxWireFormatMessage_Release(CCNxWireFormatMessage **message)
+{
+ ccnxTlvDictionary_Release(message);
+}
+
+bool
+ccnxWireFormatMessage_SetHopLimit(CCNxWireFormatMessage *message, uint32_t hoplimit)
+{
+ bool result = false;
+
+ ccnxWireFormatMessage_OptionalAssertValid(message);
+ CCNxWireFormatMessageInterface *impl = ccnxWireFormatMessageInterface_GetInterface(message);
+
+ if (impl != NULL) {
+ result = impl->setHopLimit(message, hoplimit);
+ }
+
+ return result;
+}
+
+bool
+ccnxWireFormatMessage_ConvertInterestToInterestReturn(CCNxWireFormatMessage *message, uint8_t returnCode)
+{
+ bool result = false;
+
+ ccnxWireFormatMessage_OptionalAssertValid(message);
+ CCNxWireFormatMessageInterface *impl = ccnxWireFormatMessageInterface_GetInterface(message);
+
+ if (impl != NULL) {
+ result = impl->convertInterestToInterestReturn(message, returnCode);
+ }
+ return result;
+}
+
diff --git a/libccnx-common/ccnx/common/ccnx_WireFormatMessage.h b/libccnx-common/ccnx/common/ccnx_WireFormatMessage.h
new file mode 100755
index 00000000..7a61e23b
--- /dev/null
+++ b/libccnx-common/ccnx/common/ccnx_WireFormatMessage.h
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @brief A structure of functions to enable accessing a CCNxTlvDictionary as a
+ * wire format object.
+ *
+ */
+
+#ifndef __CCNx_Common__ccnx_WireFormatMessage__
+#define __CCNx_Common__ccnx_WireFormatMessage__
+
+#include <ccnx/common/internal/ccnx_WireFormatMessageInterface.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+#include <parc/security/parc_CryptoHash.h>
+
+typedef CCNxTlvDictionary CCNxWireFormatMessage;
+
+/**
+ * Creates a new CCNxWireFormatMessage instance from the `wireFormat` buffer passed in.
+ * The schema version and the message type are determined from `wireFormat`.
+ *
+ * @param wireFormat - a buffer, in wire format, representing the message to created.
+ * @return A new instance of CCNxWireFormatMessage that must eventually be released by calling
+ * {@link ccnxWireFormatMessage_Release}.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ * @see ccnxWireFormatMessage_Release
+ */
+CCNxWireFormatMessage *ccnxWireFormatMessage_Create(const PARCBuffer *wireFormat);
+
+/**
+ * Creates dictionary of Interest type from the wire format
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxWireFormatMessage *ccnxWireFormatMessage_FromInterestPacketType(const CCNxTlvDictionary_SchemaVersion schemaVersion, const PARCBuffer *wireFormat);
+
+/**
+ * Creates dictionary of Interest type from the wire format
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxWireFormatMessage *ccnxWireFormatMessage_FromInterestPacketTypeIoVec(const CCNxTlvDictionary_SchemaVersion schemaVersion, const CCNxCodecNetworkBufferIoVec *vec);
+
+/**
+ * Creates a dictionary of ContentObject type from the wire format
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxWireFormatMessage *ccnxWireFormatMessage_FromContentObjectPacketType(const CCNxTlvDictionary_SchemaVersion schemaVersion, const PARCBuffer *wireFormat);
+
+/**
+ * Creates a dictionary of Control type from the wire format
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxWireFormatMessage *ccnxWireFormatMessage_FromControlPacketType(const CCNxTlvDictionary_SchemaVersion schemaVersion, const PARCBuffer *wireFormat);
+
+#ifdef Libccnx_DISABLE_VALIDATION
+# define ccnxWireFormatMessage_OptionalAssertValid(_instance_)
+#else
+# define ccnxWireFormatMessage_OptionalAssertValid(_instance_) ccnxWireFormatMessage_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `CCNxWireFormatMessage` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid CCNxWireFormatMessage instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxWireFormatMessage *a = ccnxWireFormatMessage_Create();
+ *
+ * ccnxWireFormatMessage_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * ccnxWireFormatMessage_Release(&b);
+ * }
+ * @endcode
+ */
+void ccnxWireFormatMessage_AssertValid(const CCNxWireFormatMessage *message);
+
+/**
+ * Returns the PARCBuffer that wraps the entire wireformat representation
+ *
+ * May be NULL if there is no wire format yet (e.g. you're going down the stack before the codec)
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxWireFormatMessage_GetWireFormatBuffer(const CCNxWireFormatMessage *dictionary);
+
+/**
+ * Returns the CCNxCodecNetworkBufferIoVec that wraps the entire wireformat representation
+ *
+ * May be NULL if there is no wire format yet (e.g. you're going down the stack before the codec), or it
+ * may be NULL because the wireformat is wrapped in a PARCBuffer instead.
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBufferIoVec *ccnxWireFormatMessage_GetIoVec(const CCNxWireFormatMessage *dictionary);
+
+
+/**
+ * Sets the wire format buffer in a Dictionary
+ *
+ * You can only put the wire format once. Will store its down reference to the wire format, so
+ * caller should release their copy when done with it.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return true Value was put in the dictionary
+ * @return false Value not put, likely already existed
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * }
+ * @endcode
+ */
+bool ccnxWireFormatMessage_PutWireFormatBuffer(CCNxWireFormatMessage *dictionary, PARCBuffer *buffer);
+
+/**
+ * Sets the wire format buffer in a Dictionary
+ *
+ * You can only put the wire format once. Will store its down reference to the wire format, so
+ * caller should release their copy when done with it.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return true Value was put in the dictionary
+ * @return false Value not put, likely already existed
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * }
+ * @endcode
+ */
+bool ccnxWireFormatMessage_PutIoVec(CCNxWireFormatMessage *dictionary, CCNxCodecNetworkBufferIoVec *vec);
+
+/**
+ * Writes the wire format to the specified file
+ *
+ * The file will be truncated to 0. If there is no wire format, the file will remain at 0 bytes.
+ *
+ * You can view the packet with the Wireshark plugin. First convert it to a TCP enapsulation
+ * (the program text2pcap is included as part of WireShark). The part "- filename.pcap" means that
+ * text2pcap will read from stdin (the "-") and write to "filename.pcap". Text2pcap requires a
+ * text format derived from "od" or from "hexdump".
+ *
+ * od -Ax -tx1 -v filename | text2pcap -T 9695,9695 - filename.pcap
+ * tshark -r filename.pcap -V
+ *
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxWireFormatMessage_WriteToFile(const CCNxWireFormatMessage *dictionary, const char *filename);
+
+/**
+ * Write to the dictionary the start of the protection region
+ *
+ * The protected region is the byte range that is protected by the signature (validation payload).
+ * This sets the validation region in the dictionary.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return false A validation region is already set, cannot overwrite
+ * @return true The validation region was set in the dictionary
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxWireFormatMessage_SetProtectedRegionStart(CCNxWireFormatMessage *dictionary, size_t startPosition);
+
+/**
+ * Write to the dictionary the length of the protection region
+ *
+ * The protected region is the byte range that is protected by the signature (validation payload).
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return false A validation region is already set, cannot overwrite
+ * @return true The validation region was set in the dictionary
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxWireFormatMessage_SetProtectedRegionLength(CCNxWireFormatMessage *dictionary, size_t length);
+
+/**
+ * Runs a hasher over the protected part of the wire format message
+ *
+ * The protected part of the wire format message is from the start of the CCNx Message
+ * through the end of the Validation Algorithm.
+ *
+ * If no validation algorithm block exists, then there is no protection region and
+ * we cannot compute the hash.
+ *
+ * The protection region is computed by the CCNxCodecTlvDecoder and stored in the dictionary.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return null There is no protection region
+ * @return non-null The computed hash
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCCryptoHash *ccnxWireFormatMessage_HashProtectedRegion(const CCNxWireFormatMessage *dictionary, PARCCryptoHasher *hasher);
+
+/**
+ * Calculates the ContentObject Hash, which is the SHA256 hash of the protected part of the wire format message.
+ *
+ * The protected part of the wire format message is from the start of the CCNx Message
+ * through the end of the Validation Algorithm.
+ *
+ * The protection region is computed by the CCNxCodecTlvDecoder and stored in the dictionary.
+ *
+ * This function must only be called on a dictionary that contains a ContentObject and a WireFormat buffer.
+ *
+ * @param [in] dictionary The ContentObject message on which to calculate its hash.
+ *
+ * @return null if we could not calculate the hash. This could mean the protected region wasn't set, or it wasn't a ContentObject.
+ * @return non-null The computed hash
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+PARCCryptoHash *ccnxWireFormatMessage_CreateContentObjectHash(CCNxWireFormatMessage *dictionary);
+
+/**
+ * Returns a pointer to the CCNxTlvDictionary underlying the specified CCNxWireFormatMessage.
+ *
+ * @param message - The CCNxWireFormatMessage instance from which to retrieve the CCNxTlvDictionary.
+ * @return A pointer to the underlying CCNxTlvDictionary
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxWireFormatMessage_GetDictionary(const CCNxWireFormatMessage *message);
+
+/**
+ * Increase the number of references to a `CCNxWireFormatMessage`.
+ *
+ * Note that a new `CCNxWireFormatMessage` is not created,
+ * only that the given `CCNxWireFormatMessage` reference count is incremented.
+ * Discard the reference by invoking {@link ccnxWireFormatMessage_Release}.
+ *
+ * @param [in] message A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * CCNxWireFormat *reference = ccnxWireFormatMessage_Acquire(message);
+ *
+ * ...
+ *
+ * ccnxWireFormatMessage_Release(&reference);
+ *
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxWireFormatMessage_Release}
+ */
+CCNxWireFormatMessage *ccnxWireFormatMessage_Acquire(const CCNxWireFormatMessage *message);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] messageP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxWireFormatMessage *reference = ccnxWireFormatMessage_Acquire(message);
+ *
+ * ...
+ *
+ * ccnxWireFormatMessage_Release(&reference);
+ *
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxWireFormatMessage_Acquire}
+ */
+void ccnxWireFormatMessage_Release(CCNxWireFormatMessage **messageP);
+
+/**
+ * Write a hoplimit to a messages attached wire format io vectors or buffers
+ *
+ * @param [in] message
+ * @param [in] hoplimit
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxWireFormatMessage_SetHopLimit(CCNxWireFormatMessage *message, uint32_t hoplimit);
+
+/**
+ * Given an Interest (as a CCNxWireFormatMessage), convert it to an InterestReturn and
+ * set the return code of the InterestReturn. This does not create a new instance, but
+ * simply modifies the supplied Interest in place.
+ *
+ * @param [in] message - the Interest (as a CCNxWireFormatMessage) to convert.
+ * @param [in] returnCode - the InterestReturn code to embed in the message.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxWireFormatMessage *interest = <...>;
+ *
+ * CCNxWireFormatMessage *interestReturn =
+ * ccnxWireFormatMessage_ConvertInterestToInterestReturn(interest,
+ * CCNxInterestReturn_ReturnCode_HopLimitExceeded);
+ *
+ * }
+ * @endcode
+ */
+bool ccnxWireFormatMessage_ConvertInterestToInterestReturn(CCNxWireFormatMessage *message, uint8_t returnCode);
+#endif /* defined(__CCNx_Common__ccnx_WireFormatMessage__) */
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.c b/libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.c
new file mode 100644
index 00000000..2fdab85f
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.c
@@ -0,0 +1,559 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/codec/ccnxCodec_EncodingBuffer.h>
+
+struct ccnx_tlv_encoding_buffer_linked_array;
+typedef struct ccnx_tlv_encoding_buffer_linked_array _CCNxCodecEncodingBufferLinkedArray;
+
+typedef struct array_entry {
+ struct iovec vec;
+ PARCBuffer *buffer;
+} _ArrayEntry;
+
+/**
+ * @typedef CCNxCodecEncodingBufferLinkedArray
+ * @abstract A chain of arrays of PARCBuffers
+ * @constant next The next EncodingBuffer in the chain
+ * @constant prev The previous EncodingBuffer in the chain
+ * @constant cacapcity The array capacity of bufferArray
+ * @constant count The number of items in this EncodingBuffer
+ * @constant bytes The bytes in this EncodingBuffer
+ * @constant bufferArray An array of (PARCBuffer *)
+ * @discussion If 'next' is NULL, then new elements are appendig to bufferArray. If 'next' is
+ * not null, then calls to Append will go to the bufferArray at the tail of the linked list.
+ */
+struct ccnx_tlv_encoding_buffer_linked_array {
+ // we can chain these encoding buffers together to make
+ // one long linear list
+ _CCNxCodecEncodingBufferLinkedArray *next;
+ _CCNxCodecEncodingBufferLinkedArray *prev;
+
+ // the number of elements allocated the array
+ uint32_t capacity;
+
+ // The total number of elements in this bufferArray
+ uint32_t count;
+
+ // The total bytes of this bufferArray
+ size_t bytes;
+
+ // each encoding buffer is an array of _ArrayEntry structures containing
+ // a PARCBuffer reference and a vector referencing the PARCBuffer contents.
+ _ArrayEntry *array;
+};
+
+/**
+ * @typedef CCNxCodecEncodingBuffer
+ * @abstract A chain of arrays of PARCBuffers
+ * @constant next The next EncodingBuffer in the chain
+ * @constant prev The previous EncodingBuffer in the chain
+ * @constant cacapcity The array capacity of bufferArray
+ * @constant totalCount The total number of items in this EncodingBuffer and all subsequent
+ * @constant totalBytes The total number of bytes in this EncodingBuffer and all subsequent
+ * @constant bufferArray An array of (PARCBuffer *)
+ * @discussion If 'next' is NULL, then new elements are appendig to bufferArray. If 'next' is
+ * not null, then calls to Append will go to the bufferArray at the tail of the linked list.
+ */
+struct ccnx_codec_encoding_buffer {
+ _CCNxCodecEncodingBufferLinkedArray *head;
+ _CCNxCodecEncodingBufferLinkedArray *tail;
+
+ // The total number of elements in all LinkedArrays
+ uint32_t totalCount;
+
+ // The total bytes in all LinkedArrays
+ size_t totalBytes;
+};
+
+static void _ccnxCodecEncodingBufferEntry_SetIOVec(PARCBuffer *buffer, struct iovec *iov);
+
+static const uint32_t DEFAULT_CAPACITY = 32;
+
+// ======================================================================================
+// CCNxCodecEncodingBufferLinkedArray releated
+
+static void
+_ccnxCodecEncodingBufferLinkedArray_Display(const _CCNxCodecEncodingBufferLinkedArray *array,
+ int indentation)
+{
+ printf("Entry %p prev %p next %p capacity %u count %u bytes %zu\n",
+ (void *) array, (void *) array->prev, (void *) array->next, array->capacity, array->count, array->bytes);
+
+ size_t totalBytes = 0;
+
+ for (int i = 0; i < array->count; i++) {
+ size_t bytes = array->array[i].vec.iov_len;
+ totalBytes += bytes;
+ printf(" %3d iovec_base=%p bytes=%4zu total bytes=%4zu\n",
+ i, array->array[i].vec.iov_base, bytes, totalBytes);
+ }
+}
+
+static _CCNxCodecEncodingBufferLinkedArray *
+_ccnxCodecEncodingBufferLinkedArray_Create(uint32_t capacity)
+{
+ // allocation for the object plus the array of buffers
+ _CCNxCodecEncodingBufferLinkedArray *array = parcMemory_Allocate(sizeof(_CCNxCodecEncodingBufferLinkedArray));
+ assertNotNull(array, "parcMemory_Allocate(%zu) returned NULL", sizeof(_CCNxCodecEncodingBufferLinkedArray));
+ array->capacity = capacity;
+ array->bytes = 0;
+ array->count = 0;
+ array->next = NULL;
+ array->prev = NULL;
+ array->array = parcMemory_AllocateAndClear(sizeof(_ArrayEntry) * capacity);
+ return array;
+}
+
+/**
+ * A LinkedArray can only be released if it has been removed from the EncodingBuffer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+_ccnxCodecEncodingBufferLinkedArray_Release(_CCNxCodecEncodingBufferLinkedArray **arrayPtr)
+{
+ assertNotNull(arrayPtr, "Parameter must be non-null");
+ _CCNxCodecEncodingBufferLinkedArray *array = *arrayPtr;
+
+ assertNull(array->prev, "array->prev must be null")
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(array, 0);
+ }
+
+ assertNull(array->next, "array->next must be null")
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(array, 0);
+ }
+
+ for (int i = 0; i < array->count; i++) {
+ if (array->array[i].buffer) {
+ parcBuffer_Release(&(array->array[i].buffer));
+ }
+ }
+
+ parcMemory_Deallocate(&(array->array));
+ parcMemory_Deallocate((void **) &array);
+}
+
+static void
+_ccnxCodecEncodingBufferLinkedArray_Validate(const _CCNxCodecEncodingBufferLinkedArray *array)
+{
+ assertNotNull(array, "Parameter list must be non-null");
+
+ if (array->next) {
+ assertTrue(array->next->prev == array,
+ "next->prev does not point to this entry: entry %p next %p next->prev %p",
+ (void *) array, (void *) array->next, (void *) array->next->prev)
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(array, 0);
+ }
+ }
+
+ if (array->prev) {
+ assertTrue(array->prev->next == array,
+ "prev->next does not point to this entry: entry %p prev %p prev->next %p",
+ (void *) array, (void *) array->prev, (void *) array->prev->next)
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(array, 0);
+ }
+ }
+
+ assertTrue(array->count <= array->capacity,
+ "Array count greater than capacity: count %u capacity %u",
+ array->count, array->capacity)
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(array, 0);
+ }
+
+ size_t totalBytes = 0;
+
+ for (int i = 0; i < array->count; i++) {
+ totalBytes += array->array[i].vec.iov_len;
+ }
+
+ assertTrue(totalBytes == array->bytes,
+ "Array bytes wrong, got %zu expected %zu",
+ totalBytes, array->bytes);
+}
+
+__attribute__((unused))
+static void
+_ccnxCodecEncodingBuffer_Validate(CCNxCodecEncodingBuffer *list)
+{
+ assertNotNull(list, "List is null");
+
+ // either we have both a head and a tail or neither
+ assertTrue((list->head && list->tail) || !(list->head || list->tail),
+ "List has a mixture of null head or tail: list %p head %p tail %p",
+ (void *) list, (void *) list->head, (void *) list->tail)
+ {
+ ccnxCodecEncodingBuffer_Display(list, 0);
+ }
+
+ assertTrue(list->head == NULL || list->head->prev == NULL,
+ "List head has head->prev: list %p head %p head->prev %p",
+ (void *) list, (void *) list->head, (void *) list->tail)
+ {
+ ccnxCodecEncodingBuffer_Display(list, 0);
+ }
+
+ assertTrue(list->tail == NULL || list->tail->next == NULL,
+ "List tail has tail->next: list %p tail %p tail->next %p",
+ (void *) list, (void *) list->head, (void *) list->tail)
+ {
+ ccnxCodecEncodingBuffer_Display(list, 0);
+ }
+
+
+ // walk the linked list and make sure the count is equal to what we expect
+ size_t itemCount = 0;
+ size_t totalBytes = 0;
+ _CCNxCodecEncodingBufferLinkedArray *next = list->head;
+ while (next != NULL) {
+ _ccnxCodecEncodingBufferLinkedArray_Validate(next);
+
+ itemCount += next->count;
+ totalBytes += next->bytes;
+
+ if (next->next == NULL) {
+ assertTrue(next == list->tail,
+ "Found list link with null next, but it is not tail: list %p list->tail %p entry %p",
+ (void *) list, (void *) list->tail, (void *) next)
+ {
+ ccnxCodecEncodingBuffer_Display(list, 0);
+ _ccnxCodecEncodingBufferLinkedArray_Display(next, 0);
+ }
+ }
+ next = next->next;
+ }
+
+ assertTrue(itemCount == list->totalCount, "Wrong itemCount, got %zu expected %u", itemCount, list->totalCount);
+ assertTrue(totalBytes == list->totalBytes, "Wrong totalBytes, got %zu expected %zu", totalBytes, list->totalBytes);
+}
+
+
+// ======================================================================================
+
+static void
+_ccnxCodecEncodingBuffer_Remove(CCNxCodecEncodingBuffer *list, _CCNxCodecEncodingBufferLinkedArray *array)
+{
+ if (array->prev) {
+ array->prev->next = array->next;
+ }
+
+ if (array->next) {
+ array->next->prev = array->prev;
+ }
+
+ if (list->head == array) {
+ list->head = array->next;
+ } else if (list->tail == array) {
+ list->tail = array->prev;
+ }
+
+ array->next = NULL;
+ array->prev = NULL;
+
+ assertTrue(list->totalBytes >= array->bytes,
+ "list bytes smaller than array: list %zu array %zu", list->totalBytes, array->bytes);
+ assertTrue(list->totalCount >= array->count,
+ "list count smaller than array: list %u array %u", list->totalCount, array->count);
+
+ list->totalCount -= array->count;
+ list->totalBytes -= array->bytes;
+}
+
+static void
+_ccnxCodecEncodingBuffer_FinalRelease(CCNxCodecEncodingBuffer **listBufferPtr)
+{
+ CCNxCodecEncodingBuffer *list = *listBufferPtr;
+
+ _CCNxCodecEncodingBufferLinkedArray *next = list->head;
+ while (next != NULL) {
+ _CCNxCodecEncodingBufferLinkedArray *nextnext = next->next;
+ _ccnxCodecEncodingBuffer_Remove(list, next);
+ _ccnxCodecEncodingBufferLinkedArray_Release(&next);
+ next = nextnext;
+ }
+}
+
+parcObject_ExtendPARCObject(CCNxCodecEncodingBuffer, _ccnxCodecEncodingBuffer_FinalRelease, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(ccnxCodecEncodingBuffer, CCNxCodecEncodingBuffer);
+
+parcObject_ImplementRelease(ccnxCodecEncodingBuffer, CCNxCodecEncodingBuffer);
+
+CCNxCodecEncodingBuffer *
+ccnxCodecEncodingBuffer_Create(void)
+{
+ CCNxCodecEncodingBuffer *listBuffer = parcObject_CreateInstance(CCNxCodecEncodingBuffer);
+ listBuffer->head = NULL;
+ listBuffer->tail = NULL;
+ listBuffer->totalCount = 0;
+ listBuffer->totalBytes = 0;
+ return listBuffer;
+}
+
+void
+ccnxCodecEncodingBuffer_Display(const CCNxCodecEncodingBuffer *list, int indentation)
+{
+ printf("List %p head %p tail %p itemCount %u totalBytes %zu\n",
+ (void *) list, (void *) list->head, (void *) list->tail, list->totalCount, list->totalBytes);
+
+ size_t totalCount = 0;
+ size_t totalBytes = 0;
+ size_t position = 0;
+ _CCNxCodecEncodingBufferLinkedArray *next = list->head;
+ while (next != NULL) {
+ printf(" %3zu: entry %p prev %p next %p\n",
+ position, (void *) next, (void *) next->prev, (void *) next->next);
+ _ccnxCodecEncodingBufferLinkedArray_Display(next, indentation);
+
+ totalCount += next->count;
+ totalBytes += next->bytes;
+ position++;
+ next = next->next;
+ }
+}
+
+static void
+_ccnxCodecEncodingBuffer_AppendLinkedArray(CCNxCodecEncodingBuffer *list, _CCNxCodecEncodingBufferLinkedArray *array)
+{
+ if (list->tail) {
+ list->tail->next = array;
+ } else {
+ // if list tail is null, it means list head is null too
+ list->head = array;
+ }
+
+ array->prev = list->tail;
+ list->tail = array;
+}
+
+static void
+_ccnxCodecEncodingBuffer_PrependLinkedArray(CCNxCodecEncodingBuffer *list, _CCNxCodecEncodingBufferLinkedArray *array)
+{
+ array->next = list->head;
+ array->prev = list->head->prev;
+ list->head->prev = array;
+ list->head = array;
+}
+
+size_t
+ccnxCodecEncodingBuffer_PrependBuffer(CCNxCodecEncodingBuffer *list, PARCBuffer *buffer)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+
+ _CCNxCodecEncodingBufferLinkedArray *head = list->head;
+ if ((head == NULL) || (list->head->count == list->head->capacity)) {
+ head = _ccnxCodecEncodingBufferLinkedArray_Create(DEFAULT_CAPACITY);
+ _ccnxCodecEncodingBuffer_PrependLinkedArray(list, head);
+ }
+
+ assertTrue(head->count < head->capacity, "head does not have any room left")
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(head, 0);
+ }
+
+ size_t position = list->head->count;
+ for (int i = 0; i < list->head->count; i++) {
+ head->array[i + 1] = head->array[i];
+ }
+ head->array[0].buffer = parcBuffer_Acquire(buffer);
+ _ccnxCodecEncodingBufferEntry_SetIOVec(buffer, &head->array[0].vec);
+
+ size_t bytes = head->array[0].vec.iov_len;
+ head->bytes += bytes;
+ list->totalBytes += bytes;
+
+ head->count++;
+ list->totalCount++;
+
+ return position;
+}
+
+size_t
+ccnxCodecEncodingBuffer_AppendBuffer(CCNxCodecEncodingBuffer *list, PARCBuffer *buffer)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+
+ _CCNxCodecEncodingBufferLinkedArray *tail = list->tail;
+ if (tail == NULL || list->tail->count == list->tail->capacity) {
+ tail = _ccnxCodecEncodingBufferLinkedArray_Create(DEFAULT_CAPACITY);
+ _ccnxCodecEncodingBuffer_AppendLinkedArray(list, tail);
+ }
+
+ assertTrue(tail->count < tail->capacity, "tail does not have any room left")
+ {
+ _ccnxCodecEncodingBufferLinkedArray_Display(tail, 0);
+ }
+
+ size_t position = list->totalCount;
+ tail->array[tail->count].buffer = parcBuffer_Acquire(buffer);
+ _ccnxCodecEncodingBufferEntry_SetIOVec(buffer, &tail->array[tail->count].vec);
+
+ size_t bytes = tail->array[tail->count].vec.iov_len;
+ tail->bytes += bytes;
+ list->totalBytes += bytes;
+
+ tail->count++;
+ list->totalCount++;
+
+ return position;
+}
+
+// Returns the number of elements in the list
+size_t
+ccnxCodecEncodingBuffer_Size(const CCNxCodecEncodingBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ return buffer->totalCount;
+}
+
+// Returns the total number of bytes in the list
+size_t
+ccnxCodecEncodingBuffer_Length(const CCNxCodecEncodingBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ return buffer->totalBytes;
+}
+
+// ======================================================================================
+
+// ======================================================================================
+
+static void
+_ccnxCodecEncodingBufferEntry_SetIOVec(PARCBuffer *buffer, struct iovec *iov)
+{
+ // this can return NULL for a 0 capacity entry
+ PARCByteArray *byteArray = parcBuffer_Array(buffer);
+
+ if (byteArray) {
+ uint8_t *array = parcByteArray_Array(byteArray);
+
+ // we need to advance the array so it is at the buffer's offset.
+ size_t offset = parcBuffer_ArrayOffset(buffer) + parcBuffer_Position(buffer);
+
+ iov->iov_base = (array + offset);
+ iov->iov_len = parcBuffer_Remaining(buffer);
+ } else {
+ iov->iov_base = NULL;
+ iov->iov_len = 0;
+ }
+}
+
+// Creates an iovec array pointing to the PARCBuffer contents at offset for length
+CCNxCodecEncodingBuffer *
+ccnxCodecEncodingBuffer_Slice(CCNxCodecEncodingBuffer *encodingBuffer, size_t offset, size_t length)
+{
+ CCNxCodecEncodingBuffer *listBuffer = parcObject_CreateInstance(CCNxCodecEncodingBuffer);
+ listBuffer->head = NULL;
+ listBuffer->tail = NULL;
+ listBuffer->totalCount = 0;
+ listBuffer->totalBytes = 0;
+
+ _CCNxCodecEncodingBufferLinkedArray *head;
+ head = _ccnxCodecEncodingBufferLinkedArray_Create(encodingBuffer->totalCount); // pessimistic
+ _ccnxCodecEncodingBuffer_AppendLinkedArray(listBuffer, head);
+
+ _CCNxCodecEncodingBufferLinkedArray *next = encodingBuffer->head;
+ int position = 0;
+ while (next && length) {
+ for (int i = 0; (i < next->count) && length; i++) {
+ if ((offset >= position) && (offset < (position + next->array[i].vec.iov_len))) {
+ int remainder = 0;
+ head->array[head->count].buffer = parcBuffer_Acquire(next->array[i].buffer);
+ head->array[head->count].vec.iov_base = next->array[i].vec.iov_base + (offset - position);
+ remainder = next->array[i].vec.iov_len - (offset - position);
+ if (remainder > length) {
+ remainder = length;
+ }
+ head->array[head->count].vec.iov_len = remainder;
+ offset += remainder;
+ length -= remainder;
+
+ head->count++;
+ head->bytes += remainder;
+ listBuffer->totalCount++;
+ listBuffer->totalBytes += remainder;
+ }
+ position += next->array[i].vec.iov_len;
+ }
+ next = next->next;
+ }
+ if (listBuffer->totalCount == 0) {
+ ccnxCodecEncodingBuffer_Release(&listBuffer);
+ }
+
+ return listBuffer;
+}
+
+// Creates an iovec array pointing to the PARCBuffer contents
+CCNxCodecEncodingBufferIOVec *
+ccnxCodecEncodingBuffer_CreateIOVec(CCNxCodecEncodingBuffer *encodingBuffer)
+{
+ // one allocation for the object and the array
+ size_t totalAllocation = sizeof(CCNxCodecEncodingBufferIOVec) + sizeof(struct iovec) * encodingBuffer->totalCount;
+
+ CCNxCodecEncodingBufferIOVec *vec = parcMemory_Allocate(totalAllocation);
+ assertNotNull(vec, "parcMemory_Allocate(%zu) returned NULL", totalAllocation);
+ vec->encodingBuffer = ccnxCodecEncodingBuffer_Acquire(encodingBuffer);
+ vec->iovcnt = (int) encodingBuffer->totalCount;
+
+ _CCNxCodecEncodingBufferLinkedArray *next = encodingBuffer->head;
+ int position = 0;
+ while (next) {
+ for (int i = 0; i < next->count; i++) {
+ vec->iov[position] = next->array[i].vec;
+ position++;
+ }
+ next = next->next;
+ }
+
+ return vec;
+}
+
+// releases the iovec structure, but does not release the contents. you must
+// keep at least one reference to the parent CCNxCodecEncodingBuffer alive.
+void
+ccnxCodecEncodingBufferIOVec_Release(CCNxCodecEncodingBufferIOVec **iovecPtr)
+{
+ CCNxCodecEncodingBufferIOVec *iov = *iovecPtr;
+ ccnxCodecEncodingBuffer_Release(&iov->encodingBuffer);
+ parcMemory_Deallocate((void **) &iov);
+ *iovecPtr = NULL;
+}
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.h b/libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.h
new file mode 100644
index 00000000..05563762
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_EncodingBuffer.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodec_EncodingBuffer
+ * @brief An encoding buffer is a zero-copy vectored I/O for PARCBuffers
+ *
+ * An Encoding Buffer is an ordered list of PARCBuffers that can be written by functions like
+ * writev(). You can append and append to the list and the buffers are stored only by reference.
+ *
+ * You can also append one encoding buffer to another. In this case, the buffers are moved from
+ * the previous list to the end of the new list.
+ *
+ * @code
+ * {
+ * PARCBuffer *name = parcBuffer_Wrap("marc", 4, 0, 4);
+ * PARCBuffer *space= parcBuffer_Wrap(" ", 1, 0 ,1);
+ * PARCBuffer *email= parcBuffer_Wrap("<marc@example.com>", 18, 0, 18);
+ *
+ * CCNxCodecEncodingBuffer *encodingBuffer = ccnxCodecEncodingBuffer_Create();
+ * ccnxCodecEncodingBuffer_BufferInsertTail(encodingBuffer, name);
+ * ccnxCodecEncodingBuffer_BufferInsertTail(encodingBuffer, space);
+ * parcBuffer_Release(&space);
+ * parcBuffer_Release(&name);
+ *
+ * CCNxCodecEncodingBuffer *emailBuffer = ccnxCodecEncodingBuffer_Create();
+ * ccnxCodecEncodingBuffer_BufferInsertTail(emailBuffer, email);
+ * parcBuffer_Release(&email);
+ *
+ * ccnxCodecEncodingBuffer_MoveToTail(encodingBuffer, emailBuffer);
+ * ccnxCodecEncodingBuffer_Release(&emailBuffer);
+ *
+ * CCNxCodecEncodingBufferIOVec *iov = ccnxCodecEncodingBuffer_CreateIOVec(encodingBuffer);
+ * writev(STDOUT_FILENO, iov->iov, iov->iovcnt);
+ * ccnxCodecEncodingBufferIOVec_Release(&iov);
+ *
+ * ccnxCodecEncodingBuffer_Release(&encodingBuffer);
+ * }
+ * @endcode
+ *
+ */
+
+#ifndef libccnx_ccnxCodec_EncodingBuffer_h
+#define libccnx_ccnxCodec_EncodingBuffer_h
+
+#include <sys/uio.h>
+#include <parc/algol/parc_Buffer.h>
+
+struct ccnx_codec_encoding_buffer;
+typedef struct ccnx_codec_encoding_buffer CCNxCodecEncodingBuffer;
+
+/**
+ * @typedef CCNxCodecEncodingBufferIOVec
+ * @abstract Used for writev() or similar functions
+ * @constant encodingBuffer A reference counted copy of the encoding Buffer
+ * @constant iov An allocated array of iovec entries
+ * @constant iovcnt The number of array entries
+ * @discussion <#Discussion#>
+ */
+typedef struct ccnx_tlv_encoding_buffer_iovec {
+ CCNxCodecEncodingBuffer *encodingBuffer;
+ int iovcnt;
+ struct iovec iov[];
+} CCNxCodecEncodingBufferIOVec;
+
+// ======================================================================================
+
+/**
+ * Creates an empty encoding buffer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-null An allocated encoding buffer
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecEncodingBuffer *ccnxCodecEncodingBuffer_Create(void);
+
+/**
+ * Returns a reference counted copy
+ *
+ * Caller must call ccnxCodecEncodingBuffer_Release() on all copies.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null A reference counted copy
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecEncodingBuffer *ccnxCodecEncodingBuffer_Acquire(const CCNxCodecEncodingBuffer *encodingBuffer);
+
+
+/**
+ * Release the encoding buffer and all internal references
+ *
+ * will release the list and release our reference to all enclosed PARCBuffers
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecEncodingBuffer_Release(CCNxCodecEncodingBuffer **listBufferPtr);
+
+/**
+ * Displays the structure of the encoding buffer to STDOUT
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecEncodingBuffer_Display(const CCNxCodecEncodingBuffer *encodingBuffer, int indentation);
+
+/**
+ * Appends a PARCBuffer to the encoding buffer
+ *
+ * Appends to the encoding buffer a reference count to the given buffer.
+ * The return value is the storage node used in the internal data structure.
+ *
+ * The buffer will be used from its position at the time of use (i.e. when
+ * ccnxCodecEncodingBuffer_CreateIOVec() is called). It is important that no other
+ * use of the PARCBuffer move the Position.
+ *
+ * @param [in] encodingBuffer The buffer to append to
+ * @param [in] bufferToInsert The PARCBuffer to insert at the tail of the encoding buffer.
+ *
+ * @return number The position in the encoding buffer list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecEncodingBuffer_AppendBuffer(CCNxCodecEncodingBuffer *encodingBuffer, PARCBuffer *bufferToInsert);
+
+/**
+ * Prepends a PARCBuffer to the encoding buffer
+ *
+ * Prepends to the encoding buffer a reference count to the given buffer.
+ * The return value is the storage node used in the internal data structure.
+ *
+ * The buffer will be used from its position at the time of use (i.e. when
+ * ccnxCodecEncodingBuffer_CreateIOVec() is called). It is important that no other
+ * use of the PARCBuffer move the Position.
+ *
+ * @param [in] encodingBuffer The buffer to prepend to
+ * @param [in] bufferToInsert The PARCBuffer to insert at the head of the encoding buffer.
+ *
+ * @return number The position in the encoding buffer list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecEncodingBuffer_PrependBuffer(CCNxCodecEncodingBuffer *encodingBuffer, PARCBuffer *bufferToPrepend);
+
+/**
+ * Puts the value in scratch memory
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxTlvEncodingbuffer_AppendUint16(CCNxCodecEncodingBuffer *encodingBuffer, uint16_t value);
+
+/**
+ * The number of elements in the list
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecEncodingBuffer_Size(const CCNxCodecEncodingBuffer *encodingBuffer);
+
+/**
+ * The total number of bytes in the list
+ *
+ * This is calculated as the sum of all PARCBuffer Remaining lengths in
+ * the encoding buffer.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecEncodingBuffer_Length(const CCNxCodecEncodingBuffer *encodingBuffer);
+
+// ======================================================================================
+
+/**
+ * Constructs an iovec array based on the buffers in the list
+ *
+ * The elements of the iovec array will be in the list order.
+ * Each iovec entry will point to the backing array of each PARCBuffer
+ * based on that buffers current position.
+ *
+ * This object contains a reference counted copy to the encoding buffer, so
+ * the caller can release the encoding buffer and hold on to only this object
+ * until the writev (or similar function) is done.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null The allocated IOVec structure
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecEncodingBufferIOVec *ccnxCodecEncodingBuffer_CreateIOVec(CCNxCodecEncodingBuffer *encodingBuffer);
+
+/**
+ * Constructs an iovec array based on the buffers in the list that cooresponds to offset and length
+ *
+ * The elements of the iovec array will be in the list order.
+ * Each iovec entry will point to the backing array of each PARCBuffer
+ * based on that buffers current position.
+ *
+ * This object contains a reference counted copy to the encoding buffer, so
+ * the caller can release the encoding buffer and hold on to only this object
+ * until the writev (or similar function) is done.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null The allocated IOVec structure
+ * @return null An error, or the specified offset/length is not contained in the extent
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecEncodingBuffer *ccnxCodecEncodingBuffer_Slice(CCNxCodecEncodingBuffer *encodingBuffer, size_t offset, size_t length);
+
+/**
+ * Release the iovec object.
+ *
+ * This will release the IOVec object and release its reference to the encoding
+ * buffer. If this was the last reference to the encoding buffer, all references to
+ * the underlying PARCBuffers will be released too.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecEncodingBufferIOVec_Release(CCNxCodecEncodingBufferIOVec **iovecPtr);
+
+#endif // libccnx_ccnxCodec_EncodingBuffer_h
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_Error.c b/libccnx-common/ccnx/common/codec/ccnxCodec_Error.c
new file mode 100644
index 00000000..282ec210
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_Error.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/codec/ccnxCodec_Error.h>
+
+struct error_messages {
+ CCNxCodecErrorCodes code;
+ const char *message;
+} TlvErrorMessages[] = {
+ { .code = TLV_ERR_NO_ERROR, .message = "No error" },
+ { .code = TLV_ERR_VERSION, .message = "Unsupported version" },
+ { .code = TLV_ERR_PACKETTYPE, .message = "Unsupported packet type" },
+ { .code = TLV_ERR_BEYOND_PACKET_END, .message = "Field goes beyond end of packet" },
+ { .code = TLV_ERR_TOO_LONG, .message = "Length too long for parent container" },
+ { .code = TLV_ERR_NOT_FIXED_SIZE, .message = "Fixed size Type wrong Length" },
+ { .code = TLV_ERR_DUPLICATE_FIELD, .message = "Duplicate field" },
+ { .code = TLV_ERR_EMPTY_SPACE, .message = "The sum of child TLVs did not add up to parent container length" },
+
+ // missing mandatory field errors
+ { .code = TLV_MISSING_MANDATORY, .message = "Missing mandatory field" },
+
+ { .code = TLV_ERR_DECODE, .message = "Decoding error" },
+
+ { .code = TLV_ERR_PACKETLENGTH_TOO_SHORT, .message = "Packet length less than 8" },
+ { .code = TLV_ERR_HEADERLENGTH_TOO_SHORT, .message = "Header length less than 8" },
+ { .code = TLV_ERR_PACKETLENGTHSHORTER, .message = "Packet length less than header length" },
+
+
+ // end of list sentinel, the NULL determines the end of list
+ { .code = UINT16_MAX, .message = NULL }
+};
+
+
+const char *
+ccnxCodecErrors_ErrorMessage(CCNxCodecErrorCodes code)
+{
+ for (int i = 0; TlvErrorMessages[i].message != NULL; i++) {
+ if (TlvErrorMessages[i].code == code) {
+ return TlvErrorMessages[i].message;
+ }
+ }
+ return "No error message found";
+}
+
+// ==========================================================================
+
+struct ccnx_codec_error {
+ CCNxCodecErrorCodes code;
+ const char *functionName;
+ int line;
+ size_t byteOffset;
+ unsigned refcount;
+ char *toString;
+};
+
+CCNxCodecError *
+ccnxCodecError_Create(CCNxCodecErrorCodes code, const char *func, int line, size_t byteOffset)
+{
+ CCNxCodecError *error = parcMemory_AllocateAndClear(sizeof(CCNxCodecError));
+ assertNotNull(error, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CCNxCodecError));
+ error->code = code;
+ error->functionName = func;
+ error->line = line;
+ error->byteOffset = byteOffset;
+ error->toString = NULL; // computed on the fly
+ error->refcount = 1;
+ return error;
+}
+
+CCNxCodecError *
+ccnxCodecError_Acquire(CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter error must be non-null");
+ assertTrue(error->refcount > 0, "Parameter has 0 refcount, not valid");
+
+ error->refcount++;
+ return error;
+}
+
+void
+ccnxCodecError_Release(CCNxCodecError **errorPtr)
+{
+ assertNotNull(errorPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*errorPtr, "Parameter must derefernece to non-null pointer");
+ CCNxCodecError *error = *errorPtr;
+
+ assertTrue(error->refcount > 0, "Parameter has 0 refcount, not valid");
+ error->refcount--;
+ if (error->refcount == 0) {
+ if (error->toString) {
+ // this is asprintf generated
+ free(error->toString);
+ }
+ parcMemory_Deallocate((void **) &error);
+ }
+ *errorPtr = NULL;
+}
+
+size_t
+ccnxCodecError_GetByteOffset(const CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return error->byteOffset;
+}
+
+
+CCNxCodecErrorCodes
+ccnxCodecError_GetErrorCode(const CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return error->code;
+}
+
+const char *
+ccnxCodecError_GetFunction(const CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return error->functionName;
+}
+
+int
+ccnxCodecError_GetLine(const CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return error->line;
+}
+
+const char *
+ccnxCodecError_GetErrorMessage(const CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return ccnxCodecErrors_ErrorMessage(error->code);
+}
+
+const char *
+ccnxCodecError_ToString(CCNxCodecError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ if (error->toString) {
+ return error->toString;
+ }
+
+ int failure = asprintf(&error->toString, "TLV error: %s:%d offset %zu: %s",
+ error->functionName,
+ error->line,
+ error->byteOffset,
+ ccnxCodecError_GetErrorMessage(error));
+ assertTrue(failure > -1, "Error asprintf");
+
+ return error->toString;
+}
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_Error.h b/libccnx-common/ccnx/common/codec/ccnxCodec_Error.h
new file mode 100755
index 00000000..7204cedb
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_Error.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodec_Error.h
+ * @brief Wraps an error condition in the Tlv codec
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_ccnxCodec_Error_h
+#define libccnx_ccnxCodec_Error_h
+
+#include <stdlib.h>
+#include <ccnx/common/codec/ccnxCodec_ErrorCodes.h>
+
+struct ccnx_codec_error;
+typedef struct ccnx_codec_error CCNxCodecError;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *ccnxCodecError_ErrorMessage(CCNxCodecErrorCodes code);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecError *ccnxCodecError_Create(CCNxCodecErrorCodes code, const char *func, int line, size_t byteOffset);
+
+/**
+ * Returns a reference counted copy of the error
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null A reference counted copy
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecError *ccnxCodecError_Acquire(CCNxCodecError *error);
+
+/**
+ * Releases a reference count
+ *
+ * When the reference count reaches 0, the object is destroyed.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecError_Release(CCNxCodecError **errorPtr);
+
+/**
+ * The byte offset of the error
+ *
+ * Primarily for decoding errors. It will contain the byte offset of the first byte
+ * of the field causing the error. For encoding, it will be the byte offer of the
+ * partially-encoded buffer, but the error is usually in the native format, not the
+ * partially encoded buffer.
+ *
+ * @param <#param1#>
+ * @return The byte offset of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecError_GetByteOffset(const CCNxCodecError *error);
+
+
+/**
+ * If there was a decode error, return the error code
+ *
+ * A text message is available from <code>tlvErrors_ErrorMessage()</code>.
+ *
+ * @param <#param1#>
+ * @return Returns the error code, or TVL_ERR_NO_ERROR for successful decode
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecErrorCodes ccnxCodecError_GetErrorCode(const CCNxCodecError *error);
+
+/**
+ * The function where the error occured
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *ccnxCodecError_GetFunction(const CCNxCodecError *error);
+
+/**
+ * The line where the error occured
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecError_GetLine(const CCNxCodecError *error);
+
+/**
+ * Descriptive error message
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return A static text string
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *ccnxCodecError_GetErrorMessage(const CCNxCodecError *error);
+
+/**
+ * A string representation of the entire error
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return An internally allocated string, do not destroy it
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *ccnxCodecError_ToString(CCNxCodecError *error);
+#endif // libccnx_ccnx_TlvError_h
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_ErrorCodes.h b/libccnx-common/ccnx/common/codec/ccnxCodec_ErrorCodes.h
new file mode 100755
index 00000000..938f6b20
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_ErrorCodes.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodec_ErrorCodes.h
+ * @brief The error codes used by CCNxCodecError.
+ *
+ * The codecs in schema_v0 and schema_v1 use these error codes to report problems inside
+ * CCNxCodec_TlvEncoder and CCNxCodec_TlvDecoder.
+ *
+ */
+
+#ifndef CCNx_Common_ccnxCodec_ErrorCodes_h
+#define CCNx_Common_ccnxCodec_ErrorCodes_h
+
+/**
+ * @typedef <#CCNBHeaderType#>
+ * @abstract <#Abstract#>
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum ccnx_codec_error_codes {
+ TLV_ERR_NO_ERROR,
+ TLV_ERR_VERSION,
+ TLV_ERR_PACKETTYPE,
+ TLV_ERR_BEYOND_PACKET_END,
+ TLV_ERR_TOO_LONG,
+ TLV_ERR_NOT_FIXED_SIZE,
+ TLV_ERR_DUPLICATE_FIELD,
+ TLV_ERR_EMPTY_SPACE,
+
+ // generic error for decoding error
+ TLV_ERR_DECODE,
+
+ TLV_ERR_PACKETLENGTH_TOO_SHORT,
+ TLV_ERR_HEADERLENGTH_TOO_SHORT,
+ TLV_ERR_PACKETLENGTHSHORTER,
+
+
+ // errors for missing mandatory fields
+ TLV_MISSING_MANDATORY,
+} CCNxCodecErrorCodes;
+#endif
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.c b/libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.c
new file mode 100755
index 00000000..ea1868b6
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.c
@@ -0,0 +1,809 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * We maintain a linked list of memory blocks. We fill each memory block to capacity, then
+ * allocate another memory block, putting it at the tail of the list.
+ *
+ * We maintain a "current" pointer to the memory block that holds "position". Insertions always go
+ * current block.
+ *
+ * Each memory block has a capacity and a limit. The capacity is the maximum number of bytes available.
+ * The limit is the furthest byte written. It will not exceed the capacity..
+ *
+ * Once a memory block has a "next" block, the limit is fixed. One cannot shrink or expand the limit.
+ * When the "next" pointer is set, the capacity is shrunk to the limit and the buffer is called "frozen".
+ *
+ * (always in ABSOLUTE bytes)
+ * position = 4036
+ * begin = 0 begin = 1536 begin = 3536 |
+ * | | | |
+ * +--------------------------+--------------------------+--------------------------+
+ * | block 0 | block 1 | block 2 |
+ * +--------------------------+--------------------------+--------------------------+
+ * | | | |
+ * capacity = 1536 capacity = 2000 | capacity = 2046
+ * limit = 1536 limit = 2000 limit = 500
+ * (always in RELATIVE bytes)
+ *
+ * Block 0 was allocated at 1536 bytes and filled to capacity before it was frozen.
+ *
+ * Block 1 was allocated at 2046 but only filled to 2000 bytes when it was frozen. The last 46 bytes
+ * of the block are permanently lost.
+ *
+ * Block 2 is still in use. 500 bytes have been written out of the 2046 capacity.
+ *
+ * The "begin" of a memory block is equal to the previous's memory block's "begin" plus
+ * the previous blocks "limit" when it is frozen. The "begin" value is absolute byte position
+ * and it will never change because all prior blocks must be frozen.
+ *
+ * The total "limit" of the entire chain is the tail's "begin" plus tail's "limit".
+ *
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <parc/algol/parc_Memory.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+
+struct ccnx_codec_network_buffer_memory;
+typedef struct ccnx_codec_network_buffer_memory CCNxCodecNetworkBufferMemory;
+
+struct ccnx_codec_network_buffer_memory {
+ CCNxCodecNetworkBufferMemory *next;
+
+ size_t begin; /**< Absolute position of begining */
+ size_t limit; /**< Bytes used */
+ size_t capacity; /**< maximum bytes available (end - begin) */
+
+ uint8_t *memory;
+};
+
+struct ccnx_codec_network_buffer_iovec {
+ CCNxCodecNetworkBuffer *networkBuffer;
+ unsigned refcount;
+ size_t totalBytes;
+ int iovcnt;
+ struct iovec array[];
+};
+
+struct ccnx_codec_network_buffer {
+ size_t position;
+ size_t capacity; /**< Bytes allocated */
+
+ CCNxCodecNetworkBufferMemory *current;
+ CCNxCodecNetworkBufferMemory *head;
+ CCNxCodecNetworkBufferMemory *tail;
+
+ void *userarg;
+ CCNxCodecNetworkBufferMemoryBlockFunctions memoryFunctions;
+ unsigned refcount;
+};
+
+// ================================================================================
+
+#define INLINE_POSITION(block) ((uint8_t *) block + sizeof(CCNxCodecNetworkBufferMemory))
+
+static CCNxCodecNetworkBufferMemory *
+_ccnxCodecNetworkBufferMemory_Allocate(CCNxCodecNetworkBuffer *buffer, size_t bytes)
+{
+ assertNotNull(buffer->memoryFunctions.allocator, "Allocator must be non-null to allocate memory!");
+
+ CCNxCodecNetworkBufferMemory *block;
+ size_t totalAllocation = bytes + sizeof(CCNxCodecNetworkBufferMemory);
+ size_t actual = buffer->memoryFunctions.allocator(buffer->userarg, totalAllocation, (void **) &block);
+
+ if (actual > sizeof(CCNxCodecNetworkBufferMemory)) {
+ block->next = NULL;
+ block->begin = 0;
+ block->capacity = actual - sizeof(CCNxCodecNetworkBufferMemory);
+ block->limit = 0;
+
+ block->memory = INLINE_POSITION(block);
+ return block;
+ }
+
+ // Need a de-allocator, see case 1006
+ trapOutOfMemory("Wanted %zu got %zu, minimum required %zu", totalAllocation, actual, sizeof(CCNxCodecNetworkBufferMemory));
+ return NULL;
+}
+
+/**
+ * Wrap a user-provided buffer. It will be de-allocated with the buffer memory functions.
+ *
+ * The capacity = limit = length of the user provided memory.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static CCNxCodecNetworkBufferMemory *
+_ccnxCodecNetworkBufferMemory_Wrap(CCNxCodecNetworkBuffer *buffer, size_t length, uint8_t memory[length])
+{
+ CCNxCodecNetworkBufferMemory *block = parcMemory_AllocateAndClear(sizeof(CCNxCodecNetworkBufferMemory));
+ if (block) {
+ block->next = NULL;
+ block->begin = 0;
+ block->capacity = length;
+ block->limit = length;
+ block->memory = memory;
+
+ return block;
+ }
+ trapOutOfMemory("Could not allocate a CCNxCodecNetworkBufferMemory");
+}
+
+/**
+ * Releases a memory block
+ *
+ * The memory block must not be in a linked list (i.e memory->next must be NULL)
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+_ccnxCodecNetworkBufferMemory_Release(CCNxCodecNetworkBuffer *buffer, CCNxCodecNetworkBufferMemory **memoryPtr)
+{
+ assertNotNull(memoryPtr, "Parameter must be non-null");
+ assertNotNull(*memoryPtr, "Parameter must dereference to non-null");
+
+ CCNxCodecNetworkBufferMemory *memory = *memoryPtr;
+
+ assertNull(memory->next, "memory->next is not null");
+
+ // If the memory is not in-line, free it with the deallocator
+ if (memory->memory == INLINE_POSITION(memory)) {
+ if (buffer->memoryFunctions.deallocator) {
+ buffer->memoryFunctions.deallocator(buffer->userarg, (void **) memoryPtr);
+ }
+ } else {
+ if (buffer->memoryFunctions.deallocator) {
+ buffer->memoryFunctions.deallocator(buffer->userarg, (void **) &memory->memory);
+ }
+ parcMemory_Deallocate((void **) &memory);
+ }
+
+
+ *memoryPtr = NULL;
+}
+
+static void
+_ccnxCodecNetworkBufferMemory_Display(const CCNxCodecNetworkBufferMemory *block, unsigned indent)
+{
+ assertNotNull(block, "Parameter block must be non-null");
+
+ printf("Memory block %p next %p offset %zu limit %zu capacity %zu\n",
+ (void *) block, (void *) block->next, block->begin, block->limit, block->capacity);
+
+ longBowDebug_MemoryDump((const char *) block->memory, block->capacity);
+}
+
+static bool
+_ccnxCodecNetworkBufferMemory_ContainsPosition(CCNxCodecNetworkBufferMemory *memory, size_t position)
+{
+ return (memory->begin <= position && position < memory->begin + memory->limit);
+}
+
+// ================================================================================
+
+static void
+_ccnxCodecNetworkBuffer_Expand(CCNxCodecNetworkBuffer *buffer)
+{
+ size_t allocationSize = 2048;
+ CCNxCodecNetworkBufferMemory *memory = _ccnxCodecNetworkBufferMemory_Allocate(buffer, allocationSize);
+
+ buffer->capacity += memory->capacity;
+
+ memory->begin = buffer->tail->begin + buffer->tail->limit;
+
+ // this will free the tail buffer. We will drop its capacity to its limit.
+ buffer->tail->next = memory;
+ buffer->tail->capacity = buffer->tail->limit;
+
+ buffer->tail = memory;
+}
+
+static size_t
+_ccnxCodecNetworkBuffer_RemainingCurrentBlock(CCNxCodecNetworkBuffer *buffer)
+{
+ size_t remaining = buffer->current->begin + buffer->current->capacity - buffer->position;
+ return remaining;
+}
+
+static size_t
+_ccnxCodecNetworkBuffer_BlockCount(CCNxCodecNetworkBuffer *buffer)
+{
+ // we should store this count for faster access
+ size_t count = 0;
+ CCNxCodecNetworkBufferMemory *block = buffer->head;
+ while (block) {
+ count++;
+ block = block->next;
+ }
+ return count;
+}
+
+static void
+_ccnxCodecNetworkBuffer_AllocateIfNeeded(CCNxCodecNetworkBuffer *buffer)
+{
+ if (buffer->position == buffer->current->begin + buffer->current->capacity) {
+ if (buffer->current->next) {
+ buffer->current = buffer->current->next;
+ } else {
+ // we are at the end of the current buffer and there's nothing beyond,
+ // so allocate another memory block
+ _ccnxCodecNetworkBuffer_Expand(buffer);
+ buffer->current = buffer->tail;
+ }
+ }
+}
+
+/**
+ * Check if we can fit 'length' bytes in contiguous memory.
+ *
+ * If we cannot, and the remaining buffer space in the current buffer is small, freeze it out
+ * and allocate a new buffer. Otherwise if the difference is large, do not freeze it and the
+ * write will span memory blocks.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+_ccnxCodecNetworkBuffer_EnsureRemaining(CCNxCodecNetworkBuffer *buffer, size_t length)
+{
+ // If the current block as a next pointer, then the remaining is from
+ // the position to the limit. Otherwise it is from the position to
+ // the end.
+
+ size_t remaining;
+ remaining = buffer->current->begin + buffer->current->capacity - buffer->position;
+
+
+ if (remaining < length) {
+ // If its a small amount of memory to waste, we'll freeze the curent buffer and
+ // make a new one.
+ if (length < 32 && buffer->current->next == NULL) {
+ _ccnxCodecNetworkBuffer_Expand(buffer);
+ buffer->current = buffer->tail;
+ return;
+ }
+
+ // otherwise, thre is still space in the current buffer, even though it is not
+ // long enough. The writer will just need to span the two memory blocks.
+ _ccnxCodecNetworkBuffer_AllocateIfNeeded(buffer);
+ }
+}
+
+
+// ================================================================================
+
+static size_t
+_ccnxCodecNetworkBuffer_ParcMemoryAllocator(void *userarg, size_t bytes, void **output)
+{
+ *output = parcMemory_Allocate(bytes);
+ if (*output) {
+ return bytes;
+ }
+ return 0;
+}
+
+static void
+_ccnxCodecNetworkBuffer_ParcMemoryDeallocator(void *userarg, void **memoryPtr)
+{
+ void *memory = *memoryPtr;
+ parcMemory_Deallocate((void **) &memory);
+ *memoryPtr = NULL;
+}
+
+const CCNxCodecNetworkBufferMemoryBlockFunctions ParcMemoryMemoryBlock = {
+ .allocator = &_ccnxCodecNetworkBuffer_ParcMemoryAllocator,
+ .deallocator = &_ccnxCodecNetworkBuffer_ParcMemoryDeallocator
+};
+
+CCNxCodecNetworkBuffer *
+ccnxCodecNetworkBuffer_Allocate(const CCNxCodecNetworkBufferMemoryBlockFunctions *memoryFunctions, void *userarg)
+{
+ CCNxCodecNetworkBuffer *buffer = parcMemory_Allocate(sizeof(CCNxCodecNetworkBuffer));
+ assertNotNull(buffer, "parcMemory_Allocate(%zu) returned NULL", sizeof(CCNxCodecNetworkBuffer));
+ buffer->refcount = 1;
+ buffer->position = 0;
+ memcpy(&buffer->memoryFunctions, memoryFunctions, sizeof(CCNxCodecNetworkBufferMemoryBlockFunctions));
+ buffer->userarg = userarg;
+ return buffer;
+}
+
+CCNxCodecNetworkBuffer *
+ccnxCodecNetworkBuffer_Create(const CCNxCodecNetworkBufferMemoryBlockFunctions *memoryFunctions, void *userarg)
+{
+ CCNxCodecNetworkBuffer *buffer = ccnxCodecNetworkBuffer_Allocate(memoryFunctions, userarg);
+
+ buffer->head = _ccnxCodecNetworkBufferMemory_Allocate(buffer, 1536);
+ buffer->tail = buffer->head;
+ buffer->current = buffer->head;
+ buffer->capacity = buffer->head->capacity;
+
+ return buffer;
+}
+
+CCNxCodecNetworkBuffer *
+ccnxCodecNetworkBuffer_CreateFromArray(const CCNxCodecNetworkBufferMemoryBlockFunctions *memoryFunctions, void *userarg, size_t length, uint8_t memory[length])
+{
+ CCNxCodecNetworkBuffer *buffer = ccnxCodecNetworkBuffer_Allocate(memoryFunctions, userarg);
+
+ buffer->head = _ccnxCodecNetworkBufferMemory_Wrap(buffer, length, memory);
+ buffer->tail = buffer->head;
+ buffer->current = buffer->head;
+ buffer->capacity = buffer->head->capacity;
+
+ return buffer;
+}
+
+
+
+CCNxCodecNetworkBuffer *
+ccnxCodecNetworkBuffer_Acquire(CCNxCodecNetworkBuffer *original)
+{
+ assertNotNull(original, "Parameter must be non-null");
+ assertTrue(original->refcount > 0, "Refcount must be positive, got 0");
+
+ original->refcount++;
+ return original;
+}
+
+void
+ccnxCodecNetworkBuffer_Release(CCNxCodecNetworkBuffer **bufferPtr)
+{
+ assertNotNull(bufferPtr, "Parameter must be non-null");
+ assertNotNull(*bufferPtr, "Parameter must dereference to non-null");
+
+ CCNxCodecNetworkBuffer *buffer = *bufferPtr;
+ assertTrue(buffer->refcount > 0, "refcount must be positive");
+
+ buffer->refcount--;
+ if (buffer->refcount == 0) {
+ while (buffer->head) {
+ CCNxCodecNetworkBufferMemory *next = buffer->head->next;
+ buffer->head->next = NULL;
+ _ccnxCodecNetworkBufferMemory_Release(buffer, &buffer->head);
+ buffer->head = next;
+ }
+ parcMemory_Deallocate((void **) &buffer);
+ }
+ *bufferPtr = NULL;
+}
+
+// ================================================================================
+
+static inline size_t
+_ccnxCodecNetworkBuffer_Limit(const CCNxCodecNetworkBuffer *buffer)
+{
+ return buffer->tail->begin + buffer->tail->limit;
+}
+
+size_t
+ccnxCodecNetworkBuffer_Position(const CCNxCodecNetworkBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter must be non-null");
+ return buffer->position;
+}
+
+size_t
+ccnxCodecNetworkBuffer_Limit(const CCNxCodecNetworkBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter must be non-null");
+ return _ccnxCodecNetworkBuffer_Limit(buffer);
+}
+
+void
+ccnxCodecNetworkBuffer_SetPosition(CCNxCodecNetworkBuffer *buffer, size_t position)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ assertTrue(position <= _ccnxCodecNetworkBuffer_Limit(buffer), "Position must not exceed limit, got %zu limit %zu",
+ position, _ccnxCodecNetworkBuffer_Limit(buffer));
+
+ // We allow the position to be set to the end (just past the last written byte) of the buffer.
+ // This is the "next" position to be written
+ if (position == _ccnxCodecNetworkBuffer_Limit(buffer)) {
+ buffer->current = buffer->tail;
+ } else {
+ // Is the new position within the current memory block?
+ if (_ccnxCodecNetworkBufferMemory_ContainsPosition(buffer->current, position)) {
+ // we're ok, new position is in this buffer, we're done :)
+ } else {
+ // we need to find the right buffer
+ CCNxCodecNetworkBufferMemory *memory = buffer->head;
+ while (!_ccnxCodecNetworkBufferMemory_ContainsPosition(memory, position)) {
+ memory = memory->next;
+ assertNotNull(memory, "Illegal state: position < buffer->limit, but we ran off end of linked list");
+ }
+
+ buffer->current = memory;
+ }
+ }
+
+ buffer->position = position;
+}
+
+void
+ccnxCodecNetworkBuffer_Finalize(CCNxCodecNetworkBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+
+ // if we're at the limit, we're done
+ if (buffer->position < _ccnxCodecNetworkBuffer_Limit(buffer)) {
+ // begin at the tail and free memory blocks until we've found the current position
+ size_t position = buffer->position;
+
+ // Is the new position within the current memory block?
+ if (_ccnxCodecNetworkBufferMemory_ContainsPosition(buffer->current, position)) {
+ // we're ok, new position is in this buffer, we're done :)
+ } else {
+ // we need to find the right buffer
+ CCNxCodecNetworkBufferMemory *memory = buffer->head;
+ while (!_ccnxCodecNetworkBufferMemory_ContainsPosition(memory, position)) {
+ memory = memory->next;
+ assertNotNull(memory, "Illegal state: position < buffer->limit, but we ran off end of linked list");
+ }
+
+ buffer->current = memory;
+ }
+
+ // discard any memory blocks after this
+
+ CCNxCodecNetworkBufferMemory *current = buffer->current->next;
+ while (current) {
+ CCNxCodecNetworkBufferMemory *next = current->next;
+
+ // this is a requirement for _Release to not throw an assertion
+ current->next = NULL;
+ _ccnxCodecNetworkBufferMemory_Release(buffer, &current);
+ current = next;
+ }
+
+ // Set the limit of the current block so buffer->position is the end
+ buffer->current->next = NULL;
+ size_t relativePosition = buffer->position - buffer->current->begin;
+ buffer->current->limit = relativePosition;
+ buffer->tail = buffer->current;
+ }
+}
+
+static inline void
+_ccnxCodecNetworkBuffer_PutUint8(CCNxCodecNetworkBuffer *buffer, uint8_t value)
+{
+ _ccnxCodecNetworkBuffer_AllocateIfNeeded(buffer);
+
+ size_t relativePosition = buffer->position - buffer->current->begin;
+ buffer->current->memory[relativePosition++] = value;
+ if (relativePosition > buffer->current->limit) {
+ buffer->current->limit = relativePosition;
+ }
+
+ buffer->position++;
+}
+
+void
+ccnxCodecNetworkBuffer_PutUint8(CCNxCodecNetworkBuffer *buffer, uint8_t value)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, value);
+}
+
+void
+ccnxCodecNetworkBuffer_PutUint16(CCNxCodecNetworkBuffer *buffer, uint16_t value)
+{
+ _ccnxCodecNetworkBuffer_EnsureRemaining(buffer, 2);
+
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, value >> 8);
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, value & 0xFF);
+}
+
+void
+ccnxCodecNetworkBuffer_PutUint32(CCNxCodecNetworkBuffer *buffer, uint32_t value)
+{
+ _ccnxCodecNetworkBuffer_EnsureRemaining(buffer, 4);
+
+ for (int i = sizeof(uint32_t) - 1; i > 0; i--) {
+ uint8_t b = value >> (i * 8) & 0xFF;
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, b);
+ }
+
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, value & 0xFF);
+}
+
+void
+ccnxCodecNetworkBuffer_PutUint64(CCNxCodecNetworkBuffer *buffer, uint64_t value)
+{
+ _ccnxCodecNetworkBuffer_EnsureRemaining(buffer, 8);
+
+ for (int i = sizeof(uint64_t) - 1; i > 0; i--) {
+ uint8_t b = value >> (i * 8) & 0xFF;
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, b);
+ }
+
+ _ccnxCodecNetworkBuffer_PutUint8(buffer, value & 0xFF);
+}
+
+void
+ccnxCodecNetworkBuffer_PutArray(CCNxCodecNetworkBuffer *buffer, size_t length, const uint8_t array[length])
+{
+ _ccnxCodecNetworkBuffer_AllocateIfNeeded(buffer);
+
+ size_t offset = 0;
+ while (offset < length) {
+ size_t available = _ccnxCodecNetworkBuffer_RemainingCurrentBlock(buffer);
+ if (available == 0) {
+ _ccnxCodecNetworkBuffer_AllocateIfNeeded(buffer);
+ } else {
+ if (available > (length - offset)) {
+ available = length - offset;
+ }
+
+ size_t relativePosition = buffer->position - buffer->current->begin;
+ void *dest = &buffer->current->memory[relativePosition];
+ const void *src = &array[offset];
+ memcpy(dest, src, available);
+
+ relativePosition += available;
+ if (relativePosition > buffer->current->limit) {
+ buffer->current->limit = relativePosition;
+ }
+
+ buffer->position += available;
+ offset += available;
+ }
+ }
+}
+
+void
+ccnxCodecNetworkBuffer_PutBuffer(CCNxCodecNetworkBuffer *buffer, PARCBuffer *value)
+{
+ size_t length = parcBuffer_Remaining(value);
+ if (length > 0) {
+ void *ptr = parcBuffer_Overlay(value, 0);
+ ccnxCodecNetworkBuffer_PutArray(buffer, length, ptr);
+ }
+}
+
+PARCBuffer *
+ccnxCodecNetworkBuffer_CreateParcBuffer(CCNxCodecNetworkBuffer *buffer)
+{
+ // We don't have the idea of Flip here yet, so we go from 0 .. position
+
+ size_t length = _ccnxCodecNetworkBuffer_Limit(buffer);
+ PARCBuffer *output = parcBuffer_Allocate(length);
+ CCNxCodecNetworkBufferMemory *block = buffer->head;
+ while (block) {
+ size_t available = (length > block->limit) ? block->limit : length;
+ if (available > 0) {
+ parcBuffer_PutArray(output, available, block->memory);
+ }
+ length -= available;
+ block = block->next;
+ }
+ parcBuffer_Flip(output);
+ return output;
+}
+
+PARCSignature *
+ccnxCodecNetworkBuffer_ComputeSignature(CCNxCodecNetworkBuffer *buffer, size_t start, size_t end, PARCSigner *signer)
+{
+ // Most positions (start, end, position, roof) below are in **absolute** coordinates
+ // The position relativePosition is relative to the memory block start
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ assertTrue(end >= start, "End is less than start: start %zu end %zu", start, end);
+
+ PARCSignature *signature = NULL;
+ if (signer) {
+ // compute the signature over the specified area
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(hasher);
+
+ size_t position = start;
+ CCNxCodecNetworkBufferMemory *block = buffer->head;
+ while (block && position < block->begin + block->limit) {
+ if (_ccnxCodecNetworkBufferMemory_ContainsPosition(block, position)) {
+ // determine if we're going all the way to the block's end or are we
+ // stopping early because that's the end of the designated area
+ size_t roof = (end > block->begin + block->limit) ? block->limit : end;
+ size_t length = roof - position;
+
+ // now calculate the relative offset in the block so we can update the hash
+ size_t relativePosition = position - block->begin;
+
+ parcCryptoHasher_UpdateBytes(hasher, &block->memory[relativePosition], length);
+
+ position += length;
+ }
+
+ block = block->next;
+ }
+
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+
+ signature = parcSigner_SignDigest(signer, hash);
+ parcCryptoHash_Release(&hash);
+ }
+
+ return signature;
+}
+
+uint8_t
+ccnxCodecNetworkBuffer_GetUint8(const CCNxCodecNetworkBuffer *netbuff, size_t position)
+{
+ assertNotNull(netbuff, "Parameter buffer must be non-null");
+ assertTrue(position < _ccnxCodecNetworkBuffer_Limit(netbuff), "Position %zu beyond limit %zu", position, _ccnxCodecNetworkBuffer_Limit(netbuff));
+
+ CCNxCodecNetworkBufferMemory *block = netbuff->head;
+ while (block && !_ccnxCodecNetworkBufferMemory_ContainsPosition(block, position)) {
+ block = block->next;
+ }
+
+ trapUnexpectedStateIf(block == NULL,
+ "Could not find position %zu that is less than limit %zu",
+ position, _ccnxCodecNetworkBuffer_Limit(netbuff));
+
+ size_t relativeOffset = position - block->begin;
+ return block->memory[relativeOffset];
+}
+
+void
+ccnxCodecNetworkBuffer_Display(const CCNxCodecNetworkBuffer *netbuff, unsigned indent)
+{
+ printf("CCNxCodecNetworkBuffer %p head %p current %p tail %p\n",
+ (void *) netbuff, (void *) netbuff->head, (void *) netbuff->current, (void *) netbuff->tail);
+ printf(" position %zu limit %zu capacity %zu refcount %u userarg %p\n",
+ netbuff->position, _ccnxCodecNetworkBuffer_Limit(netbuff), netbuff->capacity, netbuff->refcount, netbuff->userarg);
+
+ CCNxCodecNetworkBufferMemory *block = netbuff->head;
+ while (block) {
+ _ccnxCodecNetworkBufferMemory_Display(block, 6);
+ block = block->next;
+ }
+}
+
+// ======================================================================================
+
+
+CCNxCodecNetworkBufferIoVec *
+ccnxCodecNetworkBuffer_CreateIoVec(CCNxCodecNetworkBuffer *buffer)
+{
+ size_t blockCount = _ccnxCodecNetworkBuffer_BlockCount(buffer);
+ size_t allocationSize = sizeof(CCNxCodecNetworkBufferIoVec) + sizeof(struct iovec) * blockCount;
+
+ CCNxCodecNetworkBufferIoVec *vec = parcMemory_Allocate(allocationSize);
+ assertNotNull(vec, "parcMemory_Allocate(%zu) returned NULL", allocationSize);
+ vec->refcount = 1;
+ vec->networkBuffer = ccnxCodecNetworkBuffer_Acquire(buffer);
+ vec->iovcnt = (int) blockCount;
+ vec->totalBytes = 0;
+
+ CCNxCodecNetworkBufferMemory *block = buffer->head;
+ for (int i = 0; i < vec->iovcnt; i++) {
+ vec->array[i].iov_base = block->memory;
+ vec->array[i].iov_len = block->limit;
+ vec->totalBytes += block->limit;
+ block = block->next;
+ }
+
+ return vec;
+}
+
+CCNxCodecNetworkBufferIoVec *
+ccnxCodecNetworkBufferIoVec_Acquire(CCNxCodecNetworkBufferIoVec *vec)
+{
+ assertNotNull(vec, "Parameter vec must be non-null");
+ assertTrue(vec->refcount > 0, "Existing reference count is 0");
+ vec->refcount++;
+ return vec;
+}
+
+void
+ccnxCodecNetworkBufferIoVec_Release(CCNxCodecNetworkBufferIoVec **vecPtr)
+{
+ assertNotNull(vecPtr, "Parameter must be non-null");
+ assertNotNull(*vecPtr, "Parameter must dereference to non-null");
+ CCNxCodecNetworkBufferIoVec *vec = *vecPtr;
+ assertTrue(vec->refcount > 0, "object has 0 refcount!");
+
+ vec->refcount--;
+ if (vec->refcount == 0) {
+ ccnxCodecNetworkBuffer_Release(&vec->networkBuffer);
+ parcMemory_Deallocate((void **) &vec);
+ }
+ *vecPtr = NULL;
+}
+
+int
+ccnxCodecNetworkBufferIoVec_GetCount(CCNxCodecNetworkBufferIoVec *vec)
+{
+ assertNotNull(vec, "Parameter vec must be non-null");
+ return vec->iovcnt;
+}
+
+const struct iovec *
+ccnxCodecNetworkBufferIoVec_GetArray(CCNxCodecNetworkBufferIoVec *vec)
+{
+ assertNotNull(vec, "Parameter vec must be non-null");
+ return vec->array;
+}
+
+void
+ccnxCodecNetworkBufferIoVec_Display(const CCNxCodecNetworkBufferIoVec *vec, int indent)
+{
+ printf("\nCCNxCodecNetworkBufferIoVec %p refcount %u totalBytes %zu iovcnt %d NetworkBuffer %p\n",
+ (void *) vec, vec->refcount, vec->totalBytes, vec->iovcnt, (void *) vec->networkBuffer);
+
+ size_t total = 0;
+ for (int i = 0; i < vec->iovcnt; i++) {
+ total += vec->array[i].iov_len;
+ int nwritten = printf(" vec %3d base %p length %5zu total %5zu\n", i, (void *) vec->array[i].iov_base, vec->array[i].iov_len, total);
+ assertTrue(nwritten >= 0, "Error calling printf");
+ longBowDebug_MemoryDump(vec->array[i].iov_base, vec->array[i].iov_len);
+ }
+}
+
+size_t
+ccnxCodecNetworkBufferIoVec_Length(const CCNxCodecNetworkBufferIoVec *vec)
+{
+ assertNotNull(vec, "Parameter vec must be non-null");
+ return vec->totalBytes;
+}
+
+bool
+ccnxCodecNetworkBufferIoVec_Equals(const CCNxCodecNetworkBufferIoVec *a, const CCNxCodecNetworkBufferIoVec *b)
+{
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ // both are non-null
+ bool equals = false;
+ if (a->totalBytes == b->totalBytes) {
+ PARCBuffer *abuffer = ccnxCodecNetworkBuffer_CreateParcBuffer(a->networkBuffer);
+ PARCBuffer *bbuffer = ccnxCodecNetworkBuffer_CreateParcBuffer(b->networkBuffer);
+
+ equals = parcBuffer_Equals(abuffer, bbuffer);
+
+ parcBuffer_Release(&abuffer);
+ parcBuffer_Release(&bbuffer);
+ }
+ return equals;
+}
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.h b/libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.h
new file mode 100644
index 00000000..3ac1fffd
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_NetworkBuffer.h
@@ -0,0 +1,833 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file codec/ccnxCodec_NetworkBuffer.h
+ * @brief A network buffer represents memory used for network I/O
+ *
+ * A network buffer represents memory used for network I/O and may be scatter/gather non-contiguous memory or
+ * may be made up for special memory regions, such as DMA memory directly from the kernel.
+ *
+ * The general usage pattern of this is to create the network buffer, fill it in with the encoded packet, then
+ * create a CCNxCodecNetworkBufferIoVec from it. The IoVec is then used in a gathering write. Calling ccnxCodecNetworkBuffer_CreateIoVec()
+ * will create a CCNxCodecNetworkBufferIoVec object that has a reference to the original network buffer and will release it when the
+ * IoVec is released. A user can get a normal system "struct iovec" from the CCNxCodecNetworkBufferIoVec.
+ *
+ * The CCNxCodecNetworkBufferIoVec is a read-only object.
+ *
+ * A network buffer uses a CCNxCodecNetworkBufferMemoryBlockFunctions structure for an allocator and de-allocator. The allocator is called
+ * to add more memory to the scatter/gather list of memory buffers and the de-allocator is used to return those
+ * buffers to the owner. A user could point to "ParcMemoryMemoryBlock" to use the normal parcMemory_allocate() and
+ * parcMemory_deallocate() functions. Or, they can use their own or wrap event buffers or wrap kernel memory blocks.
+ *
+ * The user can address the memory using a linearized position with ccnxCodecNetworkBuffer_Position() and ccnxCodecNetworkBuffer_SetPosition().
+ * If a write would span two (or more) memory blocks, the write function will correctly split the write.
+ *
+ * When doing a write that would span two memory blocks, the network buffer may choose to truncate the current block and do an
+ * unsplit write to the second block. It will only do this if it would result in a small amount of wasted memory. This can only
+ * be done on the first pass through a memory block (if you set the position backwards and do a write that splits over memory blocks,
+ * the write must be split).
+ *
+ * Add a control to turn off the "optimized" write splitting (i.e. the behavior to truncate the current block and do an unsplit
+ * write to the next block).
+ *
+ * ccnxCodecNetworkBuffer_ComputeSignature should be factored out of here, like the verifier is factored out
+ *
+ */
+#ifndef Libccnx_codec_ccnxCodecNetworkBuffer_h
+#define Libccnx_codec_ccnxCodecNetworkBuffer_h
+
+#include <stdint.h>
+#include <sys/uio.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_Signer.h>
+
+struct ccnx_codec_network_buffer;
+/**
+ * @typedef CCNxCodecNetworkBuffer
+ * @brief A network buffer represents memory used for network I/O.
+ */
+typedef struct ccnx_codec_network_buffer CCNxCodecNetworkBuffer;
+
+struct ccnx_codec_network_buffer_iovec;
+/**
+ * @typedef CCNxCodecNetworkBufferIoVec
+ * @brief Contains a sequence of buffers to read in which the data to be read is stored.
+ */
+typedef struct ccnx_codec_network_buffer_iovec CCNxCodecNetworkBufferIoVec;
+
+/**
+ * @typedef CCNxCodecNetworkBufferMemoryBlockFunctions
+ * @brief Structure and functions for MemoryBlocks
+ */
+
+typedef struct ccnx_codec_network_buffer_memory_block_struct {
+ /**
+ * Allocate a block of memory at least 'bytes' long.
+ *
+ * @param [in] userarg Closure, may be null.
+ * @param [in] bytes The requested number of bytes.
+ * @param [out] output The buffer to set.
+ *
+ * @return The number of bytes granted in output.
+ */
+ size_t (*allocator)(void *userarg, size_t bytes, void **output);
+
+ /**
+ * Returns (frees) a memory block.
+ *
+ * @param [in] userarg Closure, may be null.
+ * @param [out] memoryPtr The memory pointer to dellocate and NULLify.
+ */
+ void (*deallocator)(void *userarg, void **memoryPtr);
+} CCNxCodecNetworkBufferMemoryBlockFunctions;
+
+extern const CCNxCodecNetworkBufferMemoryBlockFunctions ParcMemoryMemoryBlock;
+
+/**
+ * Creates a `CCNxCodecNetworkBuffer`.
+ *
+ * The first memory block is allocated using the default settings. The parameter "userarg" will be passed
+ * to the CCNxCodecNetworkBufferMemoryBlockFunctions for allocations and de-allocations.
+ *
+ * @param [in] blockFunctions The allocator/de-allocator to use.
+ * @param [in] userarg Passed to all calls to the blockFunctions, may be NULL.
+ *
+ * @return non-null An allocated memory block using memory from blockFunctions.
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer * netbuffer = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBuffer *ccnxCodecNetworkBuffer_Create(const CCNxCodecNetworkBufferMemoryBlockFunctions *blockFunctions, void *userarg);
+
+/**
+ * Create a `CCNxCodecNetworkBuffer` from a buffer block.
+ *
+ * The first memory block of the Network Buffer will wrap the user provided memory.
+ *
+ * If the allocator is non-null then the user could append more memory blocks.
+ *
+ * The deallocator in the blockFunctions will be called on the memory when done. The userarg will
+ * be passed to the CCNxCodecNetworkBufferMemoryBlockFunctions.
+ *
+ * @param [in] blockFunctions The allocator/de-allocator to use.
+ * @param [in] userarg Passed to all calls to the blockFunctions, may be NULL.
+ * @param [in] length The length of the user-provided memory.
+ * @param [in] memory The user-provided memory.
+ *
+ * @return non-null An allocated memory block that wraps the user-provided memory.
+ * @return null An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBuffer *ccnxCodecNetworkBuffer_CreateFromArray(const CCNxCodecNetworkBufferMemoryBlockFunctions *blockFunctions, void *userarg, size_t length, uint8_t *memory);
+
+/**
+ * Increase the number of references to a `CCNxCodecNetworkBuffer`.
+ *
+ * Note that new `CCNxCodecNetworkBuffer` is not created,
+ * only that the given `CCNxCodecNetworkBuffer` reference count is incremented.
+ * Discard the reference by invoking `ccnxCodecNetworkBuffer_Release`.
+ *
+ * @param [in] original A pointer to a `CCNxCodecNetworkBuffer` instance.
+ *
+ * @return The input `CCNxCodecNetworkBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * CCNxCodecNetworkBuffer *handle = ccnxCodecNetworkBuffer_Acquire(netbuff);
+ *
+ * ...
+ *
+ * ccnxCodecNetworkBuffer_Release(&handle);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBuffer *ccnxCodecNetworkBuffer_Acquire(CCNxCodecNetworkBuffer *original);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] bufferPtr A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * CCNxCodecNetworkBuffer *handle = ccnxCodecNetworkBuffer_Acquire(netbuff);
+ *
+ * ...
+ *
+ * ccnxCodecNetworkBuffer_Release(&handle);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_Release(CCNxCodecNetworkBuffer **bufferPtr);
+
+/**
+ * Returns the linearlized cursor position in the buffer.
+ *
+ * Returns the current cursor position in linearized memory location (this does not
+ * actually linearize the memory).
+ *
+ * @param [in] buffer An allocated network buffer.
+ *
+ * @return The linearized memory position (bytes).
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position is 0 since nothing has been written yet
+ * }
+ * @endcode
+ */
+size_t ccnxCodecNetworkBuffer_Position(const CCNxCodecNetworkBuffer *buffer);
+
+/**
+ * Returns the maximum position to which is written.
+ *
+ * The maximum position of the currently written memory, as if it were linear memory. The limit
+ * will be "0" if no data has been written.
+ *
+ * @param [in] buffer An allocated network buffer.
+ *
+ * @return The lineaized capacity (bytes).
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t limit = ccnxCodecNetworkBuffer_Limit(netbuff);
+ * // limit is msg_length since the buffer was created as a wrapper for the packet_buffer
+ * }
+ * @endcode
+ */
+size_t ccnxCodecNetworkBuffer_Limit(const CCNxCodecNetworkBuffer *buffer);
+
+/**
+ * Sets the cursor position to the linearized memory location.
+ *
+ * Sets the cursor to the linearized memory location. It must not exceed {@link ccnxCodecNetworkBuffer_Limit}().
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] position The linearized buffer position.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * ccnxCodecNetworkBuffer_SetPosition(netbuff, 1);
+ * // the position is now 1, instead of 0
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_SetPosition(CCNxCodecNetworkBuffer *buffer, size_t position);
+
+/**
+ * Sets the buffer limit to the current position. Throws away anything after.
+ *
+ * The Limit will be set to the current position. Any bytes left after the new Limit are discarded
+ * and un-recoverable. This should be done after finishing writing to the buffer, especially if
+ * the buffer was backed up to discard or overwrite previous data.
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint16_t);
+ * ccnxCodecNetworkBuffer_PutUint16(netbuff, 0x1234);
+ * ccnxCodecNetworkBuffer_SetPosition(netbuff, 1);
+ * ccnxCodecNetworkBuffer_Finalize(netbuff);
+ * // the buffer is now only '0x12' and the limit is reduced to 1.
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_Finalize(CCNxCodecNetworkBuffer *buffer);
+
+/**
+ * Writes a `uint8_t` to the current cursor position, allocating as necessary
+ *
+ * Writes to the current cursor position. If the cursor is at the end of a memory block,
+ * a new memory block will be allocated. Will assert if cannot allocate more memory (or if the allocator is null).
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] value The value to write.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint8_t);
+ * ccnxCodecNetworkBuffer_PutUint8(netbuff, 0x12);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position will equal newPosition
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_PutUint8(CCNxCodecNetworkBuffer *buffer, uint8_t value);
+
+/**
+ * Writes a `uint16_t` to the current cursor position, allocating as necessary.
+ *
+ * Writes to the current cursor position. If the cursor is at the end of a memory block,
+ * a new memory block will be allocated. Will assert if cannot allocate more memory (or if the allocator is null).
+ * The value is written in network byte order.
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] value The value to write.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint16_t);
+ * ccnxCodecNetworkBuffer_PutUint16(netbuff, 0x1234);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position will equal newPosition
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_PutUint16(CCNxCodecNetworkBuffer *buffer, uint16_t value);
+
+/**
+ * Writes a `uint32_t` to the current cursor position, allocating as necessary.
+ *
+ * Writes to the current cursor position. If the cursor is at the end of a memory block,
+ * a new memory block will be allocated. Will assert if cannot allocate more memory (or if the allocator is null).
+ * The value is written in network byte order.
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] value The value to write.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint32_t);
+ * ccnxCodecNetworkBuffer_PutUint32(netbuff, 0x12345678);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position will equal newPosition
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_PutUint32(CCNxCodecNetworkBuffer *buffer, uint32_t value);
+
+/**
+ * Writes a `uint64_t` to the current cursor position, allocating as necessary
+ *
+ * Writes to the current cursor position. If the cursor is at the end of a memory block,
+ * a new memory block will be allocated. Will assert if cannot allocate more memory (or if the allocator is null).
+ * The value is written in network byte order.
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] value The value to write.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint64_t);
+ * ccnxCodecNetworkBuffer_PutUint64(netbuff, 0x1234567812345678);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position will equal newPosition
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_PutUint64(CCNxCodecNetworkBuffer *buffer, uint64_t value);
+
+/**
+ * Writes an array to the current cursor position, allocating as necessary
+ *
+ * Writes to the current cursor position. If the cursor is at the end of a memory block,
+ * a new memory block will be allocated. Will assert if cannot allocate more memory (or if the allocator is null).
+ * The value is written in array order.
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] length AThe length of the array to write.
+ * @param [in] array The value to write.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * uint8_t array[5] = {1,2,3,4,5};
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + 5;
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, array, 5);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position will equal newPosition
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_PutArray(CCNxCodecNetworkBuffer *buffer, size_t length, const uint8_t *array);
+
+/**
+ * Writes to the current cursor position, allocating as necessary
+ *
+ * Writes to the current cursor position. If the cursor is at the end of a memory block,
+ * a new memory block will be allocated. Will assert if cannot allocate more memory (or if the allocator is null).
+ * The value is written in buffer order.
+ *
+ * @param [in,out] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] value The value to write.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + 10;
+ * ccnxCodecNetworkBuffer_PutBuffer(netbuff, buffer);
+ *
+ * size_t position = ccnxCodecNetworkBuffer_Position(netbuff);
+ * // position will equal newPosition
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_PutBuffer(CCNxCodecNetworkBuffer *buffer, PARCBuffer *value);
+
+/**
+ * Creates a linearized memory buffer.
+ *
+ * Allocates a single buffer and copies the `CCNxCodecNetworkBuffer` to it.
+ *
+ * @param [in] buffer An allocated `CCNxCodecNetworkBuffer`.
+ *
+ * @return non-null A copy of the network buffer's written contents.
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint8_t);
+ * ccnxCodecNetworkBuffer_PutUint8(netbuff, 0x12);
+ *
+ * PARCBuffer *buffer = ccnxCodecNetworkBuffer_CreateParcBuffer(netbuff);
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxCodecNetworkBuffer_CreateParcBuffer(CCNxCodecNetworkBuffer *buffer);
+
+/**
+ * Runs a signer over the network buffer
+ *
+ * Runs a {@link PARCSigner} over a specified range of the network buffer
+ *
+ * @param [in] buffer An allocated `CCNxCodecNetworkBuffer`.
+ * @param [in] start The start position (must be 0 <= start < Limit)
+ * @param [in] end The last posiiton (start < end <= Limit)
+ * @param [in] signer The `PARCSigner`
+ *
+ * @return non-null The {@link PARCSignature} computed by the signer
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * parcSecurity_Init();
+ * PARCSigner *signer = parcSigner_Create(parcPublicKeySignerPkcs12Store_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256));
+ *
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint8_t);
+ * ccnxCodecNetworkBuffer_PutUint8(netbuff, 0x12);
+ *
+ * PARCSignature *sig = ccnxCodecNetworkBuffer_ComputeSignature(netbuff, 0, ccnxCodecNetworkBuffer_Limit(netbuff), signer);
+ * }
+ * @endcode
+ */
+PARCSignature *ccnxCodecNetworkBuffer_ComputeSignature(CCNxCodecNetworkBuffer *buffer, size_t start, size_t end, PARCSigner *signer);
+
+/**
+ * Get a `uint8_t` byte from the buffer, does not change position.
+ *
+ * Reads the byte at the given position. The position must be less than the buffer's limit.
+ *
+ * @param [in] netbuff An allocated memory buffer.
+ * @param [in] position Must be 0 <= position < Limit.
+ *
+ * @return number The specified byte
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint8_t);
+ * ccnxCodecNetworkBuffer_PutUint8(netbuff, 0x12);
+ *
+ * uint8_t byte = ccnxCodecNetworkBuffer_GetUint8(netbuff, 0);
+ * }
+ * @endcode
+ */
+uint8_t ccnxCodecNetworkBuffer_GetUint8(const CCNxCodecNetworkBuffer *netbuff, size_t position);
+
+/**
+ * Prints the buffer to the console.
+ *
+ * @param [in] netbuff A `CCNxCodecNetworkBuffer` instance.
+ * @param [in] indent The number of spaces by which to indent the output.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t *packet_buffer;
+ * packet_buffer = parcMemory_Allocate(msg_length);
+ * read(fd, packet_buffer, msg_length);
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, msg_length, packet_buffer);
+ *
+ * size_t newPosition = ccnxCodecNetworkBuffer_Position(netbuff) + sizeof(uint8_t);
+ * ccnxCodecNetworkBuffer_PutUint8(netbuff, 0x12);
+ *
+ * ccnxCodecNetworkBuffer_Display(netbuff, 0);
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBuffer_Display(const CCNxCodecNetworkBuffer *netbuff, unsigned indent);
+
+// ======================================================================
+// IoVec related
+
+/**
+ * Creates a read-only `CCNxCodecNetworkBufferIoVec` representation of the `CCNxCodecNetworkBuffer`.
+ *
+ * Creates a reference to the `CCNxCodecNetworkBuffer`, so the buffer will not go away until the IoVec is released.
+ * It is a zero-copy operation. The IoVec is a read-only representation. It is used to return a "struct iovec"
+ * for doing a gathering write.
+ *
+ * @param [in] buffer An allocated `CCNxCodecNetworkBuffer` (will acquire a reference to it).
+ *
+ * @return non-null An allocated {@link CCNxCodecNetworkBufferIoVec}, you must call {@link ccnxCodecNetworkBufferIoVec_Release}
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * // the memory represented by iov will be "interest_nameA"
+ * const struct iovec * iov = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+ *
+ * // final release of "netbuff" too
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBufferIoVec *ccnxCodecNetworkBuffer_CreateIoVec(CCNxCodecNetworkBuffer *buffer);
+
+/**
+ * Increase the number of references to a `CCNxCodecNetworkBufferIoVec`.
+ *
+ * Note that new `CCNxCodecNetworkBufferIoVec` is not created,
+ * only that the given `CCNxCodecNetworkBufferIoVec` reference count is incremented.
+ * Discard the reference by invoking `ccnxCodecNetworkBufferIoVec_Release`.
+ *
+ * @param [in] vec A pointer to a `CCNxCodecNetworkBufferIoVec` instance to acquire.
+ *
+ * @return The @p vec.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * CCNxCodecNetworkBufferIoVec *handle = ccnxCodecNetworkBufferIoVec_Acquire(vec);
+ * const struct iovec *iov = ccnxCodecNetworkBufferIoVec_GetArray(handle);
+ *
+ * ccnxCodecNetworkBufferIoVec_Release(&handle);
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBufferIoVec *ccnxCodecNetworkBufferIoVec_Acquire(CCNxCodecNetworkBufferIoVec *vec);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] vecPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * const struct iovec *iov = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+ *
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBufferIoVec_Release(CCNxCodecNetworkBufferIoVec **vecPtr);
+
+/**
+ * Returns the number of extents in the iovec.
+ *
+ * The number of memory buffers gathered in the iovec.
+ *
+ * @param [in] vec An allocated `CCNxCodecNetworkBufferIoVec`.
+ *
+ * @return The number of buffers gathered in the iovec.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * // the memory represented by iov will be "interest_nameA"
+ * writev(fh, ccnxCodecNetworkBufferIoVec_GetArray(vec), ccnxCodecNetworkBufferIoVec_GetCount(vec));
+ *
+ * // final release of "netbuff" too
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+int ccnxCodecNetworkBufferIoVec_GetCount(CCNxCodecNetworkBufferIoVec *vec);
+
+/**
+ * Returns an iovec representation of the memory.
+ *
+ * Returns the internal iovec representation of the memory. You do NOT need to free this.
+ *
+ * @param [in] vec An allocated `CCNxCodecNetworkBufferIoVec`.
+ *
+ * @return non-null The internal iovec representation of the memory, do not free
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * // the memory represented by iov will be "interest_nameA"
+ * writev(fh, ccnxCodecNetworkBufferIoVec_GetArray(vec), ccnxCodecNetworkBufferIoVec_GetCount(vec));
+ *
+ * // final release of "netbuff" too
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+const struct iovec *ccnxCodecNetworkBufferIoVec_GetArray(CCNxCodecNetworkBufferIoVec *vec);
+
+/**
+ * Dispalys the CCNxCodecNetworkBufferIoVec to the console.
+ *
+ * @param [in] vec A `CCNxCodecNetworkBufferIoVec` instance.
+ * @param [in] indent The number of spaces by which to indent the output.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * ccnxCodecNetworkBufferIoVec_Display(vec, 0);
+ *
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+void ccnxCodecNetworkBufferIoVec_Display(const CCNxCodecNetworkBufferIoVec *vec, int indent);
+
+/**
+ * The total bytes of all iovecs.
+ *
+ * The total number of bytes as if linearized memory.
+ *
+ * @param [in] vec An allocated `CCNxCodecNetworkBufferIoVec`.
+ *
+ * @return number The total bytes represented by all iovecs
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * size_t interestSize = ccnxCodecNetworkBufferIoVec_Length(vec);
+ * // interestSize will be the size of the linearized interest put into the network buffer
+ *
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecNetworkBufferIoVec_Length(const CCNxCodecNetworkBufferIoVec *vec);
+
+/**
+ * Determine if two `CCNxCodecNetworkBufferIoVec` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxCodecNetworkBufferIoVec` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `ccnxCodecNetworkBufferIoVec_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxCodecNetworkBufferIoVec_Equals(x, y)` must return true if and only if
+ * `ccnxCodecNetworkBufferIoVec_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxCodecNetworkBufferIoVec_Equals(x, y)` returns true and
+ * `ccnxCodecNetworkBufferIoVec_Equals(y, z)` returns true,
+ * then `ccnxCodecNetworkBufferIoVec_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxCodecNetworkBufferIoVec_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxCodecNetworkBufferIoVec_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] a A pointer to a `CCNxCodecNetworkBufferIoVec` instance.
+ * @param [in] b A pointer to a `CCNxCodecNetworkBufferIoVec` instance.
+ *
+ * @return true if `CCNxCodecNetworkBufferIoVec` x and y are equal.
+ * @return false if `CCNxCodecNetworkBufferIoVec` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * ccnxCodecNetworkBuffer_PutArray(netbuff, sizeof(interest_nameA), interest_nameA);
+ * CCNxCodecNetworkBufferIoVec *vec1 = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * CCNxCodecNetworkBufferIoVec *vec2 = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ * ccnxCodecNetworkBuffer_Release(&netbuff);
+ *
+ * if (ccnxCodecNetworkBufferIoVec_Equals(vec1, vec2)) {
+ * printf("IOVectors are equal.\n");
+ * } else {
+ * printf("IOVectors are NOT equal.\n");
+ * }
+ *
+ * ccnxCodecNetworkBufferIoVec_Release(&vec);
+ * }
+ * @endcode
+ */
+bool ccnxCodecNetworkBufferIoVec_Equals(const CCNxCodecNetworkBufferIoVec *a, const CCNxCodecNetworkBufferIoVec *b);
+#endif // Libccnx_codec_ccnxCodecNetworkBuffer_h
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.c b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.c
new file mode 100755
index 00000000..8e547743
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * We use a 2-byte T and a 2-byte L
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+struct ccnx_codec_tlv_decoder {
+ // we use a read only buffer because we want independent
+ // position and limit from whatever the user gives us.
+ PARCBuffer *buffer;
+
+ CCNxCodecError *error;
+};
+
+CCNxCodecTlvDecoder *
+ccnxCodecTlvDecoder_Create(PARCBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+
+ CCNxCodecTlvDecoder *decoder = parcMemory_AllocateAndClear(sizeof(CCNxCodecTlvDecoder));
+ assertNotNull(decoder, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CCNxCodecTlvDecoder));
+
+ // create a reference but with independent position + limit from what the user gives us
+ decoder->buffer = parcBuffer_Slice(buffer);
+
+ return decoder;
+}
+
+void
+ccnxCodecTlvDecoder_Destroy(CCNxCodecTlvDecoder **decoderPtr)
+{
+ assertNotNull(decoderPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*decoderPtr, "Parameter must dereferecne to non-null pointer");
+ CCNxCodecTlvDecoder *decoder = *decoderPtr;
+ parcBuffer_Release(&decoder->buffer);
+
+
+ if (decoder->error) {
+ ccnxCodecError_Release(&decoder->error);
+ }
+
+ parcMemory_Deallocate((void **) &decoder);
+ *decoderPtr = NULL;
+}
+
+bool
+ccnxCodecTlvDecoder_IsEmpty(CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return (!parcBuffer_HasRemaining(decoder->buffer));
+}
+
+bool
+ccnxCodecTlvDecoder_EnsureRemaining(CCNxCodecTlvDecoder *decoder, size_t bytes)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return parcBuffer_Remaining(decoder->buffer) >= bytes;
+}
+
+size_t
+ccnxCodecTlvDecoder_Remaining(const CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return parcBuffer_Remaining(decoder->buffer);
+}
+
+uint16_t
+ccnxCodecTlvDecoder_PeekType(CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ size_t position = parcBuffer_Position(decoder->buffer);
+ uint16_t type = parcBuffer_GetUint16(decoder->buffer);
+ parcBuffer_SetPosition(decoder->buffer, position);
+ return type;
+}
+
+uint16_t
+ccnxCodecTlvDecoder_GetType(CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return parcBuffer_GetUint16(decoder->buffer);
+}
+
+uint16_t
+ccnxCodecTlvDecoder_GetLength(CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return parcBuffer_GetUint16(decoder->buffer);
+}
+
+PARCBuffer *
+ccnxCodecTlvDecoder_GetValue(CCNxCodecTlvDecoder *decoder, uint16_t length)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ PARCBuffer *value = NULL;
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) {
+ value = parcBuffer_Slice(decoder->buffer);
+ parcBuffer_SetLimit(value, length);
+
+ size_t position = parcBuffer_Position(decoder->buffer);
+ position += length;
+ parcBuffer_SetPosition(decoder->buffer, position);
+ }
+
+ return value;
+}
+
+PARCBuffer *
+ccnxCodecTlvDecoder_GetBuffer(CCNxCodecTlvDecoder *decoder, uint16_t type)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+
+ PARCBuffer *output = NULL;
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) {
+ if (ccnxCodecTlvDecoder_PeekType(decoder) == type) {
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+ output = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ }
+ }
+ return output;
+}
+
+CCNxCodecTlvDecoder *
+ccnxCodecTlvDecoder_GetContainer(CCNxCodecTlvDecoder *decoder, uint16_t length)
+{
+ CCNxCodecTlvDecoder *innerDecoder = NULL;
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) {
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ innerDecoder = ccnxCodecTlvDecoder_Create(value);
+ parcBuffer_Release(&value);
+ }
+ return innerDecoder;
+}
+
+bool
+ccnxCodecTlvDecoder_GetUint8(CCNxCodecTlvDecoder *decoder, uint16_t type, uint8_t *output)
+{
+ const size_t valueLength = 1;
+ bool success = false;
+ if (parcBuffer_Remaining(decoder->buffer) >= 4 + valueLength) {
+ if (ccnxCodecTlvDecoder_PeekType(decoder) == type) {
+ // advance the buffer
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ if (ccnxCodecTlvDecoder_GetLength(decoder) == valueLength) {
+ *output = parcBuffer_GetUint8(decoder->buffer);
+ success = true;
+ }
+ }
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvDecoder_GetUint16(CCNxCodecTlvDecoder *decoder, uint16_t type, uint16_t *output)
+{
+ const size_t valueLength = 2;
+ bool success = false;
+ if (parcBuffer_Remaining(decoder->buffer) >= 4 + valueLength) {
+ if (ccnxCodecTlvDecoder_PeekType(decoder) == type) {
+ // advance the buffer
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ if (ccnxCodecTlvDecoder_GetLength(decoder) == valueLength) {
+ *output = parcBuffer_GetUint16(decoder->buffer);
+ success = true;
+ }
+ }
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvDecoder_GetUint32(CCNxCodecTlvDecoder *decoder, uint16_t type, uint32_t *output)
+{
+ const size_t valueLength = 4;
+ bool success = false;
+ if (parcBuffer_Remaining(decoder->buffer) >= 4 + valueLength) {
+ if (ccnxCodecTlvDecoder_PeekType(decoder) == type) {
+ // advance the buffer
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ if (ccnxCodecTlvDecoder_GetLength(decoder) == valueLength) {
+ *output = parcBuffer_GetUint32(decoder->buffer);
+ success = true;
+ }
+ }
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvDecoder_GetUint64(CCNxCodecTlvDecoder *decoder, uint16_t type, uint64_t *output)
+{
+ const size_t valueLength = 8;
+ bool success = false;
+ if (parcBuffer_Remaining(decoder->buffer) >= 4 + valueLength) {
+ if (ccnxCodecTlvDecoder_PeekType(decoder) == type) {
+ // advance the buffer
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ if (ccnxCodecTlvDecoder_GetLength(decoder) == valueLength) {
+ *output = parcBuffer_GetUint64(decoder->buffer);
+ success = true;
+ }
+ }
+ }
+ return success;
+}
+
+
+size_t
+ccnxCodecTlvDecoder_Position(CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return parcBuffer_Position(decoder->buffer);
+}
+
+bool
+ccnxCodecTlvDecoder_Advance(CCNxCodecTlvDecoder *decoder, uint16_t length)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ bool success = false;
+ if (parcBuffer_Remaining(decoder->buffer) >= length) {
+ size_t position = parcBuffer_Position(decoder->buffer);
+ position += length;
+ parcBuffer_SetPosition(decoder->buffer, position);
+ success = true;
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvDecoder_BufferToVarInt(PARCBuffer *buffer, uint16_t length, uint64_t *output)
+{
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ assertNotNull(output, "Parameter output must be non-null");
+
+ bool success = false;
+ if (length >= 1 && length <= 8 && parcBuffer_Remaining(buffer) >= length) {
+ uint64_t value = 0;
+ for (int i = 0; i < length; i++) {
+ value = value << 8 | parcBuffer_GetUint8(buffer);
+ }
+ *output = value;
+ success = true;
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvDecoder_GetVarInt(CCNxCodecTlvDecoder *decoder, uint16_t length, uint64_t *output)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return ccnxCodecTlvDecoder_BufferToVarInt(decoder->buffer, length, output);
+}
+
+bool
+ccnxCodecTlvDecoder_HasError(const CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ if (decoder->error) {
+ return true;
+ }
+
+ return false;
+}
+
+
+bool
+ccnxCodecTlvDecoder_SetError(CCNxCodecTlvDecoder *decoder, CCNxCodecError *error)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ if (ccnxCodecTlvDecoder_HasError(decoder)) {
+ return false;
+ }
+
+ decoder->error = ccnxCodecError_Acquire(error);
+ return true;
+}
+
+
+void
+ccnxCodecTlvDecoder_ClearError(CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ if (ccnxCodecTlvDecoder_HasError(decoder)) {
+ ccnxCodecError_Release(&decoder->error);
+ }
+}
+
+
+CCNxCodecError *
+ccnxCodecTlvDecoder_GetError(const CCNxCodecTlvDecoder *decoder)
+{
+ assertNotNull(decoder, "Parameter decoder must be non-null");
+ return decoder->error;
+}
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.h b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.h
new file mode 100755
index 00000000..39cdcb94
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.h
@@ -0,0 +1,677 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodec_TlvDecoder.h
+ * @ingroup networking
+ * @brief TLV codec for messages
+ *
+ * TLV decoder
+ *
+ * Terminology:
+ * type = a field that labels a value
+ * length = the byte lenth of the value
+ * value = the data
+ * header = type + length
+ * container= a value that contains TLVs
+ *
+ * For example, in this structure, the "type 1" TLV is a container that holds a second TLV
+ * The second TLV is a terminal, and holds an opaque value.
+ *
+ * { .type = 1, .length = 20, .value = { .type = 2, .length = 16, .value ="It was a dark a " } }
+ *
+ * To decode the above example, we would use the decoder like this:
+ *
+ * @code
+ * {
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(container);
+ * unsigned type = ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * if (type == 3) {
+ * size_t end = ccnxCodecTlvDecoder_GetPosition(decoder) + length;
+ * while ( ccnxCodecTlvDecoder_GetPosition(decoder) < end ) {
+ * type = ccnxCodecTlvDecoder_GetType(decoder);
+ * length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * if (type == 1) {
+ * PARCBuffer *name = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // use name, then release it
+ * } else if (type == 2) {
+ * PARCBuffer *address = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // use address, then release it
+ * }
+ * }
+ * }
+ * PARCReadOnlyBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * }
+ * @endcode
+ *
+ * Another way to do the same parsing without having to use `ccnxCodecTlvDecoder_GetPosition' is to
+ * recursively parse each value:
+ *
+ * @code
+ * {
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(container);
+ * unsigned type = ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * PARCBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * if (type == 3) {
+ * CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_Create(value);
+ * while ( ! ccnxCodecTlvDecoder_IsEmpty(innerDecoder) ) {
+ * type = ccnxCodecTlvDecoder_GetType(decoder);
+ * length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * if (type == 1) {
+ * PARCBuffer *name = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // use name, then release it
+ * } else if (type == 2) {
+ * PARCBuffer *address = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // use address, then release it
+ * }
+ * }
+ * ccnxCodecTlvDecoder_Destroy(&innerDecoder);
+ * }
+ * PARCReadOnlyBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * }
+ * @endcode
+ *
+ * And an even cleaner way is to use ccnxCodecTlvDecoder_GetContainer to pull out sub-decoders
+ *
+ * @code
+ * {
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(container);
+ * unsigned type = ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * if (type == 3) {
+ * CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_GetContainer(decoder, length);
+ * while ( ! ccnxCodecTlvDecoder_IsEmpty(innerDecoder) ) {
+ * type = ccnxCodecTlvDecoder_GetType(decoder);
+ * length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * if (type == 1) {
+ * PARCBuffer *name = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // use name, then release it
+ * } else if (type == 2) {
+ * PARCBuffer *address = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // use address, then release it
+ * }
+ * }
+ * ccnxCodecTlvDecoder_Destroy(&innerDecoder);
+ * }
+ * PARCReadOnlyBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * }
+ * @endcode
+ *
+ */
+
+#ifndef libccnx_ccnx_TlvDecoder_h
+#define libccnx_ccnx_TlvDecoder_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_Signature.h>
+
+#include <ccnx/common/codec/ccnxCodec_Error.h>
+
+
+struct ccnx_codec_tlv_decoder;
+typedef struct ccnx_codec_tlv_decoder CCNxCodecTlvDecoder;
+
+/**
+ * Decodes a TLV-encoded buffer to individual buffers for each Value
+ *
+ * Walks through a TLV-encoded buffer returning buffer slices of the
+ * original. These are 0-copy operations.
+ *
+ * The decoder should be based on the CCNxCodecNetworkBufferIoVec, see case 1009
+ *
+ * @param [in] buffer The buffer to parse, must be ready to read.
+ *
+ * @return non-null A TLV decoder
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ * ccnxCodecTlvDecoder_Destroy(&decoder);
+ * }
+ * @endcode
+ */
+CCNxCodecTlvDecoder *ccnxCodecTlvDecoder_Create(PARCBuffer *buffer);
+
+/**
+ * Releases the tlv decoder.
+ *
+ * Buffers that have been previously returned remain acquired. The internal
+ * reference to the input buffer will be released.
+ *
+ * @param [in] decoderPtr Pointer to the decoder to destroy
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ * ccnxCodecTlvDecoder_Destroy(&decoder);
+ * }
+ * @endcode
+ */
+void ccnxCodecTlvDecoder_Destroy(CCNxCodecTlvDecoder **decoderPtr);
+
+/**
+ * Tests if there is anything left to decode
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return true There are more bytes available
+ * @return false At the end of the buffer
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_IsEmpty(CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Checks if there are at least `bytes' bytes remaining in the buffer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return true There are at least `bytes' bytes left
+ * @return false Buffer underrun
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_EnsureRemaining(CCNxCodecTlvDecoder *decoder, size_t bytes);
+
+/**
+ * Returns the bytes remaining in the decoder
+ *
+ * The remaining bytes to be decoded
+ *
+ * @param [in] decoder An allocated decoder
+ *
+ * @retval number The bytes left to decode
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecTlvDecoder_Remaining(const CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Gets the next bytes as the TLV type
+ *
+ * The buffer is advanced the width of the type
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * // GetType |--------|
+ * // GetLength |--------|
+ * // GetValue |--------------------|
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ * unsigned type = ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * PARCBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // value = 0x01020304
+ * }
+ * @endcode
+ */
+uint16_t ccnxCodecTlvDecoder_GetType(CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Returns the TLV Type but does not advance the decoder
+ *
+ * At the current position, decode the next bytes as the TLV type
+ *
+ * @param [in] decoder The Decoder object
+ *
+ * @return number The TLV type
+ *
+ * Example:
+ * @code
+ * {
+ * // PeekType |--------|
+ * // GetType |--------|
+ * // GetLength |--------|
+ * // GetValue |--------------------|
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ * unsigned type = ccnxCodecTlvDecoder_PeekType(decoder);
+ * if( type == 0xAABB ) {
+ * (void) ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * PARCBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // value = 0x01020304
+ * }
+ * }
+ * @endcode
+ */
+uint16_t ccnxCodecTlvDecoder_PeekType(CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Gets the next bytes as the TLV length
+ *
+ * The buffer is advanced the width of the length
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * // GetType |--------|
+ * // GetLength |--------|
+ * // GetValue |--------------------|
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ * unsigned type = ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * PARCBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // value = 0x01020304
+ * }
+ * @endcode
+ */
+uint16_t ccnxCodecTlvDecoder_GetLength(CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Returns the next `length' bytes as a value
+ *
+ * The buffer is advanced `length' bytes. The returned value is ready for reading.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * // GetType |--------|
+ * // GetLength |--------|
+ * // GetValue |--------------------|
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ * unsigned type = ccnxCodecTlvDecoder_GetType(decoder);
+ * unsigned length = ccnxCodecTlvDecoder_GetLength(decoder);
+ * PARCBuffer * value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ * // value = 0x01020304
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxCodecTlvDecoder_GetValue(CCNxCodecTlvDecoder *decoder, uint16_t length);
+
+/**
+ * Ensure the current position is of type `type', then return a buffer of the value
+ *
+ * If the buffer points to a type of `type', the function will create a buffer of
+ * the specified length and return the value in a buffer.
+ *
+ * The function will return NULL if the types don't match or if there is a
+ * a decoder underrun (its not as long as the type specifies), or if the length would
+ * take the end of the input buffer.
+ *
+ * @param [in] decoder The TLV decoder object
+ * @param [in] type The type type to validate
+ *
+ * @return non-null A conforming buffer
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * // GetBuffer |--------------------------------------------|
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 8, 0, 8);
+ *
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ *
+ * PARCBuffer *buffer = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB);
+ * // buffer contains { 0x01, 0x02, 0x03, 0x04 }
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxCodecTlvDecoder_GetBuffer(CCNxCodecTlvDecoder *decoder, uint16_t type);
+
+/**
+ * The current location is a TLV container (a value that is TLVs)
+ *
+ * Returns a TLV decoder that represents the "slice" of the input buffer from
+ * the current position up to the current position plus `length'.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null A new sub-decoder
+ * @return null An error, such as input underrun
+ *
+ * Example:
+ * @code
+ * {
+ * // GetType |--------|
+ * // GetLength |--------|
+ * // GetContainer |--------------------------------------------|
+ * // GetBuffer |--------------------------------------------|
+ * PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) {0x00, 0x01, 0x00, 0x08, 0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}, 12, 0, 12);
+ *
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+ *
+ * uint16_t containerType = ccnxCodecTlvDecoder_GetType(decoder);
+ * size_t containerLength = ccnxCodecTlvDecoder_GetLength(decoder);
+ * CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_GetContainer(decoder, containerLength);
+ * PARCBuffer *buffer = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB);
+ *
+ * ccnxCodecTlvDecoder_Destroy(&innerDecoder);
+ * ccnxCodecTlvDecoder_Destroy(&decoder);
+ *
+ * // buffer contains { 0x01, 0x02, 0x03, 0x04 }
+ * }
+ * @endcode
+ */
+CCNxCodecTlvDecoder *ccnxCodecTlvDecoder_GetContainer(CCNxCodecTlvDecoder *decoder, uint16_t length);
+
+/**
+ * Decodes the current location as a type, length, and uint8_t value.
+ *
+ * Ensures the type is `type' and returns the value as a uint8_t. If the type
+ * does not match or there is buffer underflow, the function will return false and
+ * the output will be unchanged. If the TLV length is not "1", it will also return false.
+ * Otherwise, it returns true and the decoded value.
+ *
+ * On success, the decoder is advanced, on failure the decoder will remain at the
+ * current position.
+ *
+ * @param [in] decoder The decoder object
+ * @param [in] type The TLV type to validate
+ * @param [out] output The output value
+ *
+ * @return true output parameter is valid
+ * @return false on error (type did not match or buffer underflow)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x01, 0xFF }, 5, 0, 5 );
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * uint8_t value;
+ * bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value);
+ * assert(success && value == 0xFF);
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_GetUint8(CCNxCodecTlvDecoder *decoder, uint16_t type, uint8_t *output);
+
+/**
+ * Decodes the current location as a type, length, and uint16_t value.
+ *
+ * Ensures the type is `type' and returns the value as a uint16_t. If the type
+ * does not match or there is buffer underflow, the function will return false and
+ * the output will be unchanged. If the TLV length is not "2", it will also return false.
+ * Otherwise, it returns true and the decoded value.
+ *
+ * On success, the decoder is advanced, on failure the decoder will remain at the
+ * current position.
+ *
+ * @param [in] decoder The decoder object
+ * @param [in] type The TLV type to validate
+ * @param [out] output The output value
+ *
+ * @return true output parameter is valid
+ * @return false on error (type did not match or buffer underflow)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x02, 0xFF, 0xAA }, 6, 0, 6 );
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * uint16_t value;
+ * bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value);
+ * assert(success && value == 0xFFAA);
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_GetUint16(CCNxCodecTlvDecoder *decoder, uint16_t type, uint16_t *output);
+
+/**
+ * Decodes the current location as a type, length, and uint32_t value.
+ *
+ * Ensures the type is `type' and returns the value as a uint32_t. If the type
+ * does not match or there is buffer underflow, the function will return false and
+ * the output will be unchanged. If the TLV length is not "4", it will also return false.
+ * Otherwise, it returns true and the decoded value.
+ *
+ * On success, the decoder is advanced, on failure the decoder will remain at the
+ * current position.
+ *
+ * @param [in] decoder The decoder object
+ * @param [in] type The TLV type to validate
+ * @param [out] output The output value
+ *
+ * @return true output parameter is valid
+ * @return false on error (type did not match or buffer underflow)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x04, 0xFF, 0xAA, 0xBB, 0xCC }, 8, 0, 8 );
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * uint32_t value;
+ * bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value);
+ * assert(success && value == 0xFFAABBCC);
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_GetUint32(CCNxCodecTlvDecoder *decoder, uint16_t type, uint32_t *output);
+
+/**
+ * Decodes the current location as a type, length, and uint64_t value.
+ *
+ * Ensures the type is `type' and returns the value as a uint64_t. If the type
+ * does not match or there is buffer underflow, the function will return false and
+ * the output will be unchanged. If the TLV length is not "8", it will also return false.
+ * Otherwise, it returns true and the decoded value.
+ *
+ * On success, the decoder is advanced, on failure the decoder will remain at the
+ * current position.
+ *
+ * @param [in] decoder The decoder object
+ * @param [in] type The TLV type to validate
+ * @param [out] output The output value
+ *
+ * @return true output parameter is valid
+ * @return false on error (type did not match or buffer underflow)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0xAA, 0xBB, 0xCC, 0x00, 0x00, 0x00, 0x00 }, 12, 0, 12 );
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * uint64_t value;
+ * bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value);
+ * assert(success && value == 0xFFAABBCC00000000ULL);
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_GetUint64(CCNxCodecTlvDecoder *decoder, uint16_t type, uint64_t *output);
+
+/**
+ * Returns the current byte position of the buffer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecTlvDecoder_Position(CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Advance the decoder a given number of bytes
+ *
+ * Advance the decoder, throwing away a given number of bytes.
+ * If there are not enough bytes left in the decoder, no action is taken
+ *
+ * @param [in] decoder The decoder to advance
+ * @param [in] length The number of bytes to skip
+ *
+ * @return true Advanced the buffer
+ * @return false Error, likely a buffer underrun (not enough bytes)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_Advance(CCNxCodecTlvDecoder *decoder, uint16_t length);
+
+/**
+ * Decode the current position as a VarInt
+ *
+ * A VarInt may be 1 to 8 bytes long. It is interpreted as an unsigned
+ * integer in network byte order.
+ *
+ * @param [in] decoder The TLV decoder
+ * @param [in] length The number of bytes in the varint
+ * @param [out] output The value of the varint
+ *
+ * @return true Successful decode
+ * @return fale Error (length too long, too short, or not enough bytes in decoder)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00 }, 3, 0, 3 );
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * uint64_t value;
+ * ccnxCodecTlvDecoder_GetVarInt(decoder, 3, &value);
+ * // value = 0x0000000000102300
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_GetVarInt(CCNxCodecTlvDecoder *decoder, uint16_t length, uint64_t *output);
+
+
+/**
+ * Decode the current position of the Buffer as a VarInt out to 'length' bytes
+ *
+ * A VarInt may be 1 to 8 bytes long. It is interpreted as an unsigned
+ * integer in network byte order. The buffer must have at least 'length' bytes remaining.
+ * The buffer is advanced.
+ *
+ * @param [in] decoder The TLV decoder
+ * @param [in] length The number of bytes in the varint
+ * @param [out] output The value of the varint
+ *
+ * @return true Successful decode
+ * @return fale Error (length too long, too short, or not enough bytes in decoder)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00 }, 3, 0, 3 );
+ * uint64_t value;
+ * ccnxCodecTlvDecoder_BufferToVarInt(buffer, 3, &value);
+ * // value = 0x0000000000102300
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_BufferToVarInt(PARCBuffer *buffer, uint16_t length, uint64_t *output);
+
+/**
+ * Determines if the TLV Encoder has an error condition set
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_HasError(const CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Sets an error condition. Only one error condition may be set.
+ *
+ * Stores a reference counted copy of the CCNxCodecError. If an error is already set,
+ * this function returns false and does not store a reference count. The previous error
+ * stays as the current error.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return true Error condition set
+ * @return false Error already set, you must clear it first
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvDecoder_SetError(CCNxCodecTlvDecoder *decoder, CCNxCodecError *error);
+
+/**
+ * Clears the error condition, if any
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecTlvDecoder_ClearError(CCNxCodecTlvDecoder *decoder);
+
+/**
+ * Retrieves the error message
+ *
+ * Retrieves the error condition, if any. If no error is set, will return NULL.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null The error condition set
+ * @return null No error condition is set
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecError *ccnxCodecTlvDecoder_GetError(const CCNxCodecTlvDecoder *encoder);
+#endif // libccnx_ccnx_TlvDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.c b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.c
new file mode 100755
index 00000000..bfc52234
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * We use a 2-byte T and a 2-byte L
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+
+#define NONE_SET 0
+#define START_SET 1
+#define END_SET 2
+#define BOTH_SET 3
+
+struct ccnx_codec_tlv_encoder {
+ CCNxCodecNetworkBuffer *buffer;
+
+ // OR of NONE_SET, START_SET, END_SET
+ int signatureStartEndSet;
+
+ size_t signatureStart;
+ size_t signatureEnd;
+
+ CCNxCodecError *error;
+ PARCSigner *signer;
+};
+
+CCNxCodecTlvEncoder *
+ccnxCodecTlvEncoder_Create(void)
+{
+ CCNxCodecTlvEncoder *encoder = parcMemory_AllocateAndClear(sizeof(CCNxCodecTlvEncoder));
+ assertNotNull(encoder, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CCNxCodecTlvEncoder));
+
+ encoder->buffer = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ encoder->signatureStartEndSet = NONE_SET;
+ encoder->error = NULL;
+
+ return encoder;
+}
+
+void
+ccnxCodecTlvEncoder_Destroy(CCNxCodecTlvEncoder **encoderPtr)
+{
+ assertNotNull(encoderPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*encoderPtr, "Parameter must dereferecne to non-null pointer");
+ CCNxCodecTlvEncoder *encoder = *encoderPtr;
+
+ ccnxCodecNetworkBuffer_Release(&encoder->buffer);
+
+ if (encoder->error) {
+ ccnxCodecError_Release(&encoder->error);
+ }
+
+ if (encoder->signer) {
+ parcSigner_Release(&encoder->signer);
+ }
+
+ parcMemory_Deallocate((void **) &encoder);
+ *encoderPtr = NULL;
+}
+
+CCNxCodecTlvEncoder *
+ccnxCodecTlvEncoder_Initialize(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ return encoder;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendBuffer(CCNxCodecTlvEncoder *encoder, uint16_t type, PARCBuffer *value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ assertTrue(parcBuffer_Remaining(value) <= UINT16_MAX, "Value length too long, got %zu maximum %u\n", parcBuffer_Remaining(value), UINT16_MAX);
+
+ size_t bytes = 4 + parcBuffer_Remaining(value);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, parcBuffer_Remaining(value));
+ ccnxCodecNetworkBuffer_PutBuffer(encoder->buffer, value);
+
+ return bytes;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendArray(CCNxCodecTlvEncoder *encoder, uint16_t type, uint16_t length, const uint8_t array[length])
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, length);
+ ccnxCodecNetworkBuffer_PutArray(encoder->buffer, length, array);
+ return length + 4;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendContainer(CCNxCodecTlvEncoder *encoder, uint16_t type, uint16_t length)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, length);
+ return 4;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendUint8(CCNxCodecTlvEncoder *encoder, uint16_t type, uint8_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, 1);
+ ccnxCodecNetworkBuffer_PutUint8(encoder->buffer, value);
+ return 5;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendUint16(CCNxCodecTlvEncoder *encoder, uint16_t type, uint16_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, 2);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, value);
+ return 6;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendUint32(CCNxCodecTlvEncoder *encoder, uint16_t type, uint32_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, 4);
+ ccnxCodecNetworkBuffer_PutUint32(encoder->buffer, value);
+ return 8;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendUint64(CCNxCodecTlvEncoder *encoder, uint16_t type, uint64_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, 8);
+ ccnxCodecNetworkBuffer_PutUint64(encoder->buffer, value);
+ return 12;
+}
+
+static unsigned
+_ccnxCodecTlvEncoder_ComputeVarIntLength(uint64_t value)
+{
+ unsigned length = 8;
+ if (value <= 0x00000000000000FFULL) {
+ length = 1;
+ } else if (value <= 0x000000000000FFFFULL) {
+ length = 2;
+ } else if (value <= 0x0000000000FFFFFFULL) {
+ length = 3;
+ } else if (value <= 0x00000000FFFFFFFFULL) {
+ length = 4;
+ } else if (value <= 0x000000FFFFFFFFFFULL) {
+ length = 5;
+ } else if (value <= 0x0000FFFFFFFFFFFFULL) {
+ length = 6;
+ } else if (value <= 0x00FFFFFFFFFFFFFFULL) {
+ length = 7;
+ }
+
+ return length;
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendVarInt(CCNxCodecTlvEncoder *encoder, uint16_t type, uint64_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+
+ unsigned length = _ccnxCodecTlvEncoder_ComputeVarIntLength(value);
+
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, type);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, length);
+
+ // See case 1007
+ bool mustContinue = false;
+ for (int byte = 7; byte >= 0; byte--) {
+ uint8_t b = (value >> (byte * 8)) & 0xFF;
+ if (b != 0 || byte == 0 || mustContinue) {
+ ccnxCodecNetworkBuffer_PutUint8(encoder->buffer, b);
+ mustContinue = true;
+ }
+ }
+
+ return length + 4;
+}
+
+size_t
+ccnxCodecTlvEncoder_Position(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ return ccnxCodecNetworkBuffer_Position(encoder->buffer);
+}
+
+size_t
+ccnxCodecTlvEncoder_SetPosition(CCNxCodecTlvEncoder *encoder, size_t position)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ assertTrue(position <= ccnxCodecNetworkBuffer_Limit(encoder->buffer),
+ "position beyond end of buffer, got %zu maximum %zu",
+ position, ccnxCodecNetworkBuffer_Limit(encoder->buffer));
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, position);
+ return position;
+}
+
+void
+ccnxCodecTlvEncoder_SetContainerLength(CCNxCodecTlvEncoder *encoder, size_t offset, uint16_t length)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+
+ size_t currentPosition = ccnxCodecNetworkBuffer_Position(encoder->buffer);
+
+ // +2 because we skip over the Type field
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, offset + 2);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, length);
+
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, currentPosition);
+}
+
+void
+ccnxCodecTlvEncoder_Finalize(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+
+ // set the limit to whatever our current possition is. That will truncate the
+ // packet in case we wrote beyond where we are now.
+
+ ccnxCodecNetworkBuffer_Finalize(encoder->buffer);
+}
+
+PARCBuffer *
+ccnxCodecTlvEncoder_CreateBuffer(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+
+ PARCBuffer *output = ccnxCodecNetworkBuffer_CreateParcBuffer(encoder->buffer);
+ return output;
+}
+
+CCNxCodecNetworkBufferIoVec *
+ccnxCodecTlvEncoder_CreateIoVec(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ return ccnxCodecNetworkBuffer_CreateIoVec(encoder->buffer);
+}
+
+size_t
+ccnxCodecTlvEncoder_AppendRawArray(CCNxCodecTlvEncoder *encoder, size_t length, uint8_t array[length])
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ ccnxCodecNetworkBuffer_PutArray(encoder->buffer, length, array);
+ return length;
+}
+
+size_t
+ccnxCodecTlvEncoder_PutUint8(CCNxCodecTlvEncoder *encoder, size_t offset, uint8_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ size_t position = ccnxCodecNetworkBuffer_Position(encoder->buffer);
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, offset);
+ ccnxCodecNetworkBuffer_PutUint8(encoder->buffer, value);
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, position);
+ return 1;
+}
+
+size_t
+ccnxCodecTlvEncoder_PutUint16(CCNxCodecTlvEncoder *encoder, size_t offset, uint16_t value)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ size_t position = ccnxCodecNetworkBuffer_Position(encoder->buffer);
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, offset);
+ ccnxCodecNetworkBuffer_PutUint16(encoder->buffer, value);
+ ccnxCodecNetworkBuffer_SetPosition(encoder->buffer, position);
+ return 2;
+}
+
+void
+ccnxCodecTlvEncoder_MarkSignatureStart(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ encoder->signatureStart = ccnxCodecNetworkBuffer_Position(encoder->buffer);
+ encoder->signatureStartEndSet |= START_SET;
+}
+
+void
+ccnxCodecTlvEncoder_MarkSignatureEnd(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ encoder->signatureEnd = ccnxCodecNetworkBuffer_Position(encoder->buffer);
+ encoder->signatureStartEndSet |= END_SET;
+}
+
+PARCSignature *
+ccnxCodecTlvEncoder_ComputeSignature(CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ assertTrue(encoder->signatureStartEndSet == BOTH_SET, "Did not set both start and end positions");
+
+ return ccnxCodecNetworkBuffer_ComputeSignature(encoder->buffer, encoder->signatureStart, encoder->signatureEnd, encoder->signer);
+}
+
+bool
+ccnxCodecTlvEncoder_HasError(const CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ if (encoder->error) {
+ return true;
+ }
+
+ return false;
+}
+
+bool
+ccnxCodecTlvEncoder_SetError(CCNxCodecTlvEncoder *encoder, CCNxCodecError *error)
+{
+ if (ccnxCodecTlvEncoder_HasError(encoder)) {
+ return false;
+ }
+
+ encoder->error = ccnxCodecError_Acquire(error);
+ return true;
+}
+
+void
+ccnxCodecTlvEncoder_ClearError(CCNxCodecTlvEncoder *encoder)
+{
+ if (ccnxCodecTlvEncoder_HasError(encoder)) {
+ ccnxCodecError_Release(&encoder->error);
+ }
+}
+
+CCNxCodecError *
+ccnxCodecTlvEncoder_GetError(const CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ return encoder->error;
+}
+
+void
+ccnxCodecTlvEncoder_SetSigner(CCNxCodecTlvEncoder *encoder, PARCSigner *signer)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ if (encoder->signer) {
+ parcSigner_Release(&encoder->signer);
+ }
+
+ if (signer) {
+ encoder->signer = parcSigner_Acquire(signer);
+ } else {
+ encoder->signer = NULL;
+ }
+}
+
+PARCSigner *
+ccnxCodecTlvEncoder_GetSigner(const CCNxCodecTlvEncoder *encoder)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ return encoder->signer;
+}
+
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.h b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.h
new file mode 100644
index 00000000..443eeca0
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvEncoder.h
@@ -0,0 +1,755 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodec_TlvEncoder.h
+ * @ingroup networking
+ * @brief TLV codec for messages
+ *
+ * TLV encoder
+ *
+ * Terminology:
+ * type = a field that labels a value
+ * length = the byte lenth of the value
+ * value = the data
+ * header = type + length
+ * container= a value that contains TLVs
+ *
+ * For example, in this structure, the "type 1" TLV is a container that holds a second TLV
+ * The second TLV is a terminal, and holds an opaque value.
+ *
+ * { .type = 1, .length = 20, .value = { .type = 2, .length = 16, .value ="It was a dark a " } }
+ *
+ * Example to encode a container that wraps a name and an address:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *nameAndAddress = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ *
+ * // Initialize starts a new buffer
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 3, nameAndAddress);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *container = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ *
+ * parcBuffer_Destroy(&nameAndAddress);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ *
+ * // now use the container for something...
+ * }
+ * @endcode
+ *
+ * The TLV will look something like this:
+ * @code
+ * { .type = 3, .length = L1 + L2 + overhead, .value = {
+ * {.type = 1, .length = L1, .value = name},
+ * {.type = 2, .length = L2, .value = address}
+ * }
+ * }
+ * @endcode
+ *
+ * An alternative way to encode it that does not require recursive encoder is to use Position:
+ * @code
+ * {
+ * // Creates {{T=3, L=length, V={{T=1, L=..., V=name}, {T=2, L=..., V=address}}}}
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * size_t offset = ccnxCodecTlvEncoder_Position(encoder);
+ * ccnxCodecTlvEncoder_AppendContainer(encoder, 3, 0);
+ * size_t length = 0;
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 1, name);
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, address);
+ * ccnxCodecTlvEncoder_SetContainerLength(encoder, offset, length);
+ * }
+ * @endcode
+ *
+ */
+
+#ifndef libccnx_ccnx_TlvEncoder_h
+#define libccnx_ccnx_TlvEncoder_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_Signature.h>
+
+#include <ccnx/common/codec/ccnxCodec_Error.h>
+
+// ======================================================
+
+struct ccnx_codec_tlv_encoder;
+typedef struct ccnx_codec_tlv_encoder CCNxCodecTlvEncoder;
+
+/**
+ * Creates a TLV encoder
+ *
+ * The encoder is re-usable, as the state is reset for each Initialize.
+ *
+ * @return non-null A TLV encoder
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecTlvEncoder *ccnxCodecTlvEncoder_Create(void);
+
+/**
+ * Destroys the TLV encoder and all internal state
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_Destroy(CCNxCodecTlvEncoder **encoderPtr);
+
+/**
+ * Initialize the encoder to start a new encoding
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] tlv <#description#>
+ *
+ * @return non-null The encoder
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+CCNxCodecTlvEncoder *ccnxCodecTlvEncoder_Initialize(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Appends a TL container and a PARCBuffer to the enoder
+ *
+ * The type is from the parameter `type', the length is from the remaining size
+ * of the value buffer, and the value comes from `value'.
+ *
+ * @param [in] encoder The encoder to append to
+ * @param [in] type The TLV type
+ * @param [in] value The length is the remaining buffer size, the position is advanced.
+ *
+ * @return number The total bytes of the TLV, including the T and L.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendBuffer(CCNxCodecTlvEncoder *encoder, uint16_t type, PARCBuffer *value);
+
+/**
+ * Appends a "TL" container then the bytes of the array
+ *
+ * Writes a Type of 'type' and Length of 'length' then appends 'length' bytes from
+ * the array to the encoder.
+ *
+ * @param [in] encoder An allocated CCnxCodecTlvEncoder
+ * @param [in] type The TLV type
+ * @param [in] length The TLV length
+ * @param [in] array The bytes to append
+ *
+ * @return number The number of bytes appended (including the T and L)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendArray(CCNxCodecTlvEncoder *encoder, uint16_t type, uint16_t length, const uint8_t *array);
+
+/**
+ * Appends a TL without a V.
+ *
+ * Appends a T and L without a V. Useful for doing a heirarchical encoding where the V
+ * will be more TLVs. You will either need to know L or go back and fix it up.
+ *
+ * @param [in] encoder The encoder to modify
+ * @param [in] type The TLV type
+ * @param [in] length The TLV length, use 0 if you do not know.
+ *
+ * @return bytes The bytes appended (the size of the T and L)
+ *
+ * Example:
+ * @code
+ * {
+ * // Creates {{ T=99, L=.., V=SequenceNumber }, {T=1, L=length, V={{T=2, L=..., V=name}, {T=3, L=..., V=address}}}}
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendBuffer(encoder, 99, sequenceNumber);
+ * size_t offset = ccnxCodecTlvEncoder_Position(encoder);
+ * ccnxCodecTlvEncoder_AppendContainer(encoder, 1, 0);
+ * size_t length = 0;
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, name);
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 3, address);
+ * ccnxCodecTlvEncoder_SetContainerLength(encoder, offset, length);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendContainer(CCNxCodecTlvEncoder *encoder, uint16_t type, uint16_t length);
+
+/**
+ * Adds a TLV with an 8-bit value
+ *
+ * Uses network byte order for the value. The returned size includes
+ * the type and length lengths plus the value length.
+ *
+ * @param [in] encoder The TLV encoder
+ * @param [in] type The Type value to use for the container
+ * @param [in] value The value to encode
+ *
+ * @return number The number of bytes appended to the encoded (5)
+ *
+ * Example:
+ * @code
+ * {
+ * // encoded buffer with be { .type = 1, .length = 1, .value = 0x19 }
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendUint8(encoder, 1, (uint8_t) 25);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendUint8(CCNxCodecTlvEncoder *encoder, uint16_t type, uint8_t value);
+
+/**
+ * Adds a TLV with a 16-bit value
+ *
+ * Uses network byte order for the value. The returned size includes
+ * the type and length lengths plus the value length.
+ *
+ * @param [in] encoder The TLV encoder
+ * @param [in] type The Type value to use for the container
+ * @param [in] value The value to encode
+ *
+ * @return number The number of bytes appended to the encoded (6)
+ *
+ * Example:
+ * @code
+ * {
+ * // encoded buffer with be { .type = 1, .length = 2, .value = 0x1234 }
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendUint16(encoder, 1, (uint16_t) 0x1234);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendUint16(CCNxCodecTlvEncoder *encoder, uint16_t type, uint16_t value);
+
+/**
+ * Adds a TLV with a 32-bit value
+ *
+ * Uses network byte order for the value. The returned size includes
+ * the type and length lengths plus the value length.
+ *
+ * @param [in] encoder The TLV encoder
+ * @param [in] type The Type value to use for the container
+ * @param [in] value The value to encode
+ *
+ * @return number The number of bytes appended to the encoded (8)
+ *
+ * Example:
+ * @code
+ * {
+ * // encoded buffer with be { .type = 1, .length = 4, .value = 0x12345678 }
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendUint32(encoder, 1, (uint32_t) 0x12345678);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendUint32(CCNxCodecTlvEncoder *encoder, uint16_t type, uint32_t value);
+
+
+/**
+ * Adds a TLV with a 64-bit value
+ *
+ * Uses network byte order for the value. The returned size includes
+ * the type and length lengths plus the value length.
+ *
+ * @param [in] encoder The TLV encoder
+ * @param [in] type The Type value to use for the container
+ * @param [in] value The value to encode
+ *
+ * @return number The number of bytes appended to the encoded (8)
+ *
+ * Example:
+ * @code
+ * {
+ * // encoded buffer with be { .type = 1, .length = 8, .value = 0x0000000012345678 }
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendUint64(encoder, 1, (uint64_t) 0x12345678);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendUint64(CCNxCodecTlvEncoder *encoder, uint16_t type, uint64_t value);
+
+/**
+ * Returns the current encoding buffer position
+ *
+ * This is useful if you need to backtrack to fill in a length you did not know before.
+ *
+ * @param [in] encoder The Tlv encoder object
+ *
+ * @return number The byte offset of the encode buffer
+ *
+ * Example:
+ * @code
+ * {
+ * // Creates {{ T=99, L=.., V=SequenceNumber }, {T=1, L=length, V={{T=2, L=..., V=name}, {T=3, L=..., V=address}}}}
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendBuffer(encoder, 99, sequenceNumber);
+ * size_t offset = ccnxCodecTlvEncoder_Position(encoder);
+ * ccnxCodecTlvEncoder_AppendContainer(encoder, 1, 0);
+ * size_t length = 0;
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, name);
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 3, address);
+ * ccnxCodecTlvEncoder_SetContainerLength(encoder, offset, length);
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_Position(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Used to rewind and erase
+ *
+ * For example, you called ccnxCodecTlvEncoder_AppendContainer() then found out that
+ * the container was empty. If you rewind to just before you added the container, it
+ * is as if the container were never added.
+ *
+ * @param [in] position Must be no more than ccnxCodecTlvEncoder_Position()
+ *
+ * @return number The position after calling SetPosition
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_SetPosition(CCNxCodecTlvEncoder *encoder, size_t position);
+
+/**
+ * Sets the length field of the container at the given offset
+ *
+ * User `ccnxCodecTlvEncoder_Position' before `ccnxCodecTlvEncoder_AppendContainer' to get the container's
+ * offset. You can then set that container's length with this function.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ * @param [in] offset position of the container in the Tlv Encoder
+ * @param [in] length The container length to set
+ *
+ * Example:
+ * @code
+ * {
+ * // Creates {{ T=99, L=.., V=SequenceNumber }, {T=1, L=length, V={{T=2, L=..., V=name}, {T=3, L=..., V=address}}}}
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_AppendBuffer(encoder, 99, sequenceNumber);
+ * size_t offset = ccnxCodecTlvEncoder_Position(encoder);
+ * ccnxCodecTlvEncoder_AppendContainer(encoder, 1, 0);
+ * size_t length = 0;
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, name);
+ * length += ccnxCodecTlvEncoder_AppendBuffer(encoder, 3, address);
+ * ccnxCodecTlvEncoder_SetContainerLength(encoder, offset, length);
+ * }
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_SetContainerLength(CCNxCodecTlvEncoder *encoder, size_t offset, uint16_t length);
+
+/**
+ * Finalizes the encoding and returns the encoded buffer
+ *
+ * The buffer is ready for reading. In specific, it will truncate the buffer at the
+ * current position, setting the Limit to that location. This will cut off any
+ * writes to the buffer that have been "erased" by setting the position to an
+ * earlier location.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_Finalize(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Creates a PARCBuffer from position 0 to the Limit.
+ *
+ * Returns a PARCBuffer from position 0 to the Limit. If the user has called
+ * ccnxCodecTlvEncoder_SetPosition() to rewind the buffer, the user should likely call
+ * ccnxCodecTlvEncoder_Finalize() to trim the Limit, otherwise there may be unexpected
+ * bytes at the end.
+ *
+ * The PARCBuffer representation is not the native form of the buffer and will result
+ * in a deep copy of the buffer.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return non-null An allocated PARCBuffer, use parcBuffer_Release() on it
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxCodecTlvEncoder_CreateBuffer(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Creates a vectored I/O representation of the encoder
+ *
+ * Returns a CCNxCodecNetworkBufferIoVec from position 0 to the Limit. If the user has called
+ * ccnxCodecTlvEncoder_SetPosition() to rewind the buffer, the user should likely call
+ * ccnxCodecTlvEncoder_Finalize() to trim the Limit, otherwise there may be unexpected
+ * bytes at the end.
+ *
+ * The CCNxCodecNetworkBufferIoVec is the native form of the memory and does not involve any copies.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return non-null An allocated CCNxCodecNetworkBufferIoVec, use CCNxCodecNetworkBufferIoVec_Release() on it
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Initialize(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_Finalize(encoder);
+ * CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder);
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBufferIoVec *ccnxCodecTlvEncoder_CreateIoVec(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Marks the current position as the start of the signature
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_MarkSignatureStart(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_MarkSignatureEnd(encoder);
+ *
+ * // The signature is calcualted over the TLV field of the "address"
+ * PARCSignature *sig = ccnxCodecTlvEncoder_ComputeSignature(encoder, signer);
+ *
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_MarkSignatureStart(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Marks the current position as the end (non-inclusive) of the Signature
+ * Example:
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_MarkSignatureStart(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_MarkSignatureEnd(encoder);
+ *
+ * // The signature is calcualted over the TLV field of the "address"
+ * PARCSignature *sig = ccnxCodecTlvEncoder_ComputeSignature(encoder, signer);
+ *
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_MarkSignatureEnd(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Computes the cryptographic signature over the designated area.
+ * If both a Start and End have not been set, function will assert
+ *
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @retval non-null An allocated PARCSignature
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ * ccnxCodecTlvEncoder_Append(encoder, 1, name);
+ * ccnxCodecTlvEncoder_MarkSignatureStart(encoder);
+ * ccnxCodecTlvEncoder_Append(encoder, 2, address);
+ * ccnxCodecTlvEncoder_MarkSignatureEnd(encoder);
+ *
+ * // The signature is calcualted over the TLV field of the "address"
+ * ccnxCodecTlvEncoder_SetSigner(signer);
+ * PARCSignature *sig = ccnxCodecTlvEncoder_ComputeSignature(encoder);
+ *
+ * ccnxCodecTlvEncoder_Destroy(&encoder);
+ * }
+ * @endcode
+ */
+PARCSignature *ccnxCodecTlvEncoder_ComputeSignature(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Puts a uint8_t at the specified position.
+ *
+ * Does not modify the current position of the Tlv Encoder
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return number The number of bytes put
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_PutUint8(CCNxCodecTlvEncoder *encoder, size_t offset, uint8_t value);
+
+/**
+ * Puts a uint16_t at the specified position.
+ *
+ * Does not modify the current position of the Tlv Encoder
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return number The number of bytes put
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_PutUint16(CCNxCodecTlvEncoder *encoder, size_t offset, uint16_t value);
+
+/**
+ * Writes an array to the current position. No "TL" container is written.
+ *
+ * Unlike ccnxCodecTlvEncoder_AppendArray, this does not append a Type and Length container for the array.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ * @param [in] length The number of bytes from array to write
+ * @param [in] array The source array
+ *
+ * @return number The number of bytes appended to the encoder
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendRawArray(CCNxCodecTlvEncoder *encoder, size_t length, uint8_t *array);
+
+
+/**
+ * Determines if the TLV Encoder has an error condition set
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @retval true An error condition is set
+ * @retval false No error condition is set
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvEncoder_HasError(const CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Sets an error condition. Only one error condition may be set.
+ *
+ * Stores a reference counted copy of the CCNxCodecError. If an error is already set,
+ * this function returns false and does not store a reference to the error. The previous error
+ * stays as the current error.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return true Error condition set
+ * @return false Error already set, you must clear it first
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvEncoder_SetError(CCNxCodecTlvEncoder *encoder, CCNxCodecError *error);
+
+/**
+ * Clears the error condition, if any
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_ClearError(CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Retrieves the error message
+ *
+ * Retrieves the error condition, if any. If no error is set, will return NULL.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return non-null The error condition set
+ * @return null No error condition is set
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecError *ccnxCodecTlvEncoder_GetError(const CCNxCodecTlvEncoder *encoder);
+
+
+/**
+ * Associates a signer with the encoder for producing signatures or MACs
+ *
+ * Stores a reference counted copy of the signer. The reference will be released with the
+ * CCNxCodecTlvEncoder is released or if this function is called multiple times.
+ *
+ * It is allowed to set a NULL singer.
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ * @param [in] singer Assocaited a PARCSigner with the encoder, storing a reference to it
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxCodecTlvEncoder_SetSigner(CCNxCodecTlvEncoder *encoder, PARCSigner *signer);
+
+/**
+ * Returns the PARCSigner associated with the encoder, if any
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] encoder An allocated CCNxCodecTlvEncoder
+ *
+ * @return non-null The signer assocated with the encoder
+ * @return null There is no singer associated with the encoder
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSigner *ccnxCodecTlvEncoder_GetSigner(const CCNxCodecTlvEncoder *encoder);
+
+/**
+ * Appends a TLV container holding the value as a VarInt
+ *
+ * A VarInt may be 1 to 8 bytes long. It is interpreted as an unsigned
+ * integer in network byte order. The value of "0" is encoded as a single
+ * byte of "0".
+ *
+ * @param [in] decoder The TLV decoder
+ * @param [in] type The Type value to use for the container
+ * @param [in] value The value of the varint
+ *
+ * @return number The number of bytes appended
+ *
+ * Example:
+ * @code
+ * {
+ * uint64_t value = 0x0000000000102300
+ * size_t length = ccnxCodecTlvEncoder_AppendVarInt(encoder, 12, value);
+ * // length = 7
+ * // appedned { 0x00, 0x0C, 0x00, 0x03, 0x10, 0x23, 0x00 }
+ * }
+ * @endcode
+ */
+size_t ccnxCodecTlvEncoder_AppendVarInt(CCNxCodecTlvEncoder *encoder, uint16_t type, uint64_t value);
+
+#endif // libccnx_ccnx_TlvEncoder_h
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.c b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.c
new file mode 100755
index 00000000..9df01867
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <LongBow/runtime.h>
+#include <arpa/inet.h>
+#include <ccnx/common/codec/ccnxCodec_TlvPacket.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+
+static CCNxTlvDictionary *
+_decodeV1(PARCBuffer *packetBuffer)
+{
+ CCNxTlvDictionary *packetDictionary = NULL;
+
+ CCNxCodecSchemaV1Types_PacketType packetType = (CCNxCodecSchemaV1Types_PacketType) parcBuffer_GetAtIndex(packetBuffer, 1);
+
+ switch (packetType) {
+ case CCNxCodecSchemaV1Types_PacketType_Interest:
+ packetDictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ break;
+
+ case CCNxCodecSchemaV1Types_PacketType_ContentObject:
+ packetDictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ break;
+
+ case CCNxCodecSchemaV1Types_PacketType_InterestReturn:
+ // not implemented yet
+ break;
+
+ case CCNxCodecSchemaV1Types_PacketType_Control:
+ packetDictionary = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+ break;
+
+ default:
+ // unknown type
+ break;
+ }
+
+ if (packetDictionary) {
+ // The packetBuffer may be padded or have extraneous content after the CCNx message.
+ // Ensure that the buffer limit reflects the CCNx packet length as the decoder uses
+ // the that limit, not the packetLength from the header, to determine when to stop parsing.
+ size_t packetBufferLength = ccnxCodecTlvPacket_GetPacketLength(packetBuffer);
+ assertTrue(packetBufferLength <= parcBuffer_Remaining(packetBuffer), "Short packet buffer");
+ parcBuffer_SetLimit(packetBuffer, packetBufferLength);
+ bool success = ccnxCodecSchemaV1PacketDecoder_BufferDecode(packetBuffer, packetDictionary);
+ if (!success) {
+ ccnxTlvDictionary_Release(&packetDictionary);
+ }
+ }
+ return packetDictionary;
+}
+
+CCNxTlvDictionary *
+ccnxCodecTlvPacket_Decode(PARCBuffer *packetBuffer)
+{
+ return _decodeV1(packetBuffer);
+}
+
+bool
+ccnxCodecTlvPacket_BufferDecode(PARCBuffer *packetBuffer, CCNxTlvDictionary *packetDictionary)
+{
+ // Determine the version from the first byte of the buffer
+ uint8_t version = parcBuffer_GetAtIndex(packetBuffer, 0);
+
+ // The packetBuffer may be padded or have extraneous content after the CCNx message.
+ // Ensure that the buffer limit reflects the CCNx packet length as the decoder uses
+ // the that limit, not the packetLength from the header, to determine when to stop parsing.
+ size_t packetBufferLength = ccnxCodecTlvPacket_GetPacketLength(packetBuffer);
+ assertTrue(packetBufferLength <= parcBuffer_Remaining(packetBuffer), "Short packet buffer");
+ parcBuffer_SetLimit(packetBuffer, packetBufferLength);
+
+ bool success = false;
+ switch (version) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ success = ccnxCodecSchemaV1PacketDecoder_BufferDecode(packetBuffer, packetDictionary);
+ break;
+
+ default:
+ // will return false
+ break;
+ }
+
+ return success;
+}
+
+/*
+ * We don't have an iovec based decoder yet, so linearize the memory and use a PARCBuffer
+ * See case 903.
+ */
+bool
+ccnxCodecTlvPacket_IoVecDecode(CCNxCodecNetworkBufferIoVec *vec, CCNxTlvDictionary *packetDictionary)
+{
+ size_t iovcnt = ccnxCodecNetworkBufferIoVec_GetCount(vec);
+ const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+
+ PARCBuffer *buffer = NULL;
+ if (iovcnt == 1) {
+ buffer = parcBuffer_Wrap(array[0].iov_base, array[0].iov_len, 0, array[0].iov_len);
+ } else if (iovcnt > 1) {
+ // figure out total size, then linearize it
+ size_t totalbytes = 0;
+ for (int i = 0; i < iovcnt; i++) {
+ totalbytes += array[i].iov_len;
+ }
+
+ buffer = parcBuffer_Allocate(totalbytes);
+ for (int i = 0; i < iovcnt; i++) {
+ parcBuffer_PutArray(buffer, array[i].iov_len, array[i].iov_base);
+ }
+
+ parcBuffer_Flip(buffer);
+ } else {
+ return false;
+ }
+
+ bool success = ccnxCodecTlvPacket_BufferDecode(buffer, packetDictionary);
+ parcBuffer_Release(&buffer);
+ return success;
+}
+
+CCNxCodecNetworkBufferIoVec *
+ccnxCodecTlvPacket_DictionaryEncode(CCNxTlvDictionary *packetDictionary, PARCSigner *signer)
+{
+ CCNxTlvDictionary_SchemaVersion version = ccnxTlvDictionary_GetSchemaVersion(packetDictionary);
+
+ CCNxCodecNetworkBufferIoVec *iovec = NULL;
+ switch (version) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ iovec = ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(packetDictionary, signer);
+ break;
+
+ default:
+ // will return NULL
+ break;
+ }
+ return iovec;
+}
+
+size_t
+ccnxCodecTlvPacket_GetPacketLength(PARCBuffer *packetBuffer)
+{
+ size_t length = 0;
+
+ // Determine the version from the first byte of the buffer
+ uint8_t *header = parcBuffer_Overlay(packetBuffer, 0);
+
+ switch (header[0]) {
+ case CCNxTlvDictionary_SchemaVersion_V1: { // V1 - from metis_TlvSchemaV1.c:_totalPacketLength
+ CCNxCodecSchemaV1FixedHeader *headerV1 = (CCNxCodecSchemaV1FixedHeader *) header;
+ length = htons(headerV1->packetLength);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return length;
+}
+
+// When new versions are created they need to be incorporated here so enough header information
+// can be read to determine how to proceed.
+size_t
+ccnxCodecTlvPacket_MinimalHeaderLength()
+{
+ size_t minimumHeaderLength;
+ minimumHeaderLength = sizeof(CCNxCodecSchemaV1FixedHeader);
+ return minimumHeaderLength;
+}
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.h b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.h
new file mode 100755
index 00000000..c2690b9f
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvPacket.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file rta_TlvPacket.h
+ * @brief Encode and decode a packet using the TLV 1.1 codec
+ *
+ * Will choose the appropriate schema based on the packet version
+ *
+ */
+
+#ifndef TransportRTA_rta_TlvPacketDecoder_h
+#define TransportRTA_rta_TlvPacketDecoder_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_Signer.h>
+
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+/**
+ * Decodes a packet in to a dictionary
+ *
+ * The buffer must point to byte 0 of the FixedHeader. It may extend beyond the
+ * end of the packet.
+ *
+ * @param [in] packetBuffer The wire format representation of a packet
+ *
+ * @retval non-null An allocated dictionary
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxCodecTlvPacket_Decode(PARCBuffer *packetBuffer);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvPacket_BufferDecode(PARCBuffer *packetBuffer, CCNxTlvDictionary *packetDictionary);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecTlvPacket_IoVecDecode(CCNxCodecNetworkBufferIoVec *vec, CCNxTlvDictionary *packetDictionary);
+
+
+/**
+ * Encode the packetDictionary to wire format
+ *
+ * Will only use the PacketType from FixedHeader in the dictionary, if provided. The packet Version is based
+ * on the dictionary schema version, and the length fields of the fixed header are calculated.
+ * If the FixedHeaderDictionary is not provided, the
+ * PacketType is inferred from the type of CCNx message.
+ *
+ * The signer is not stored beyond the call to DictionaryEncode.
+ * If the dictionary already has a ValidationAlg and ValidationPayload, those are used, not the Signer.
+ * Otherwise, if the signer is not null, it is used to sign the wire format.
+ *
+ * @param [in] packetDictionary The dictionary representation of the packet to encode
+ * @param [in] signer If not NULL will be used to sign the wire format
+ *
+ * @retval non-null An IoVec that can be written to the network
+ * @retval null an error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecNetworkBufferIoVec *ccnxCodecTlvPacket_DictionaryEncode(CCNxTlvDictionary *packetDictionary, PARCSigner *signer);
+
+/**
+ * Return the length of the wire format packet based on information in the header
+ *
+ * @param [in] packetBuffer a PARCBuffer containing, at least, the wire format header
+ * @return length of the message in bytes
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecTlvPacket_GetPacketLength(PARCBuffer *packetBuffer);
+
+/**
+ * Return the minimal header that must be read to determine type and packet size
+ *
+ * @return length of the header which must be read in bytes
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecTlvPacket_MinimalHeaderLength();
+
+#endif // TransportRTA_rta_TlvPacketDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.c b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.c
new file mode 100644
index 00000000..4b90abf1
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <LongBow/runtime.h>
+
+bool
+ccnxCodecTlvUtilities_DecodeContainer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, bool (*typeDecoder)(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length))
+{
+ while (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) {
+ uint16_t type = ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) {
+ bool success = typeDecoder(decoder, packetDictionary, type, length);
+ if (!success) {
+ return false;
+ }
+ } else {
+ // overflow! The TLV length goes beyond the end of the container
+ return false;
+ }
+ }
+
+ // Make sure we used up the whole buffer. If we're at the end,
+ // then it was a successful decode, otherwise something is wrong.
+ return ccnxCodecTlvDecoder_IsEmpty(decoder);
+}
+
+bool
+ccnxCodecTlvUtilities_DecodeSubcontainer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t key, uint16_t length,
+ bool (*subcontainerDecoder)(CCNxCodecTlvDecoder *, CCNxTlvDictionary *))
+{
+ bool success = false;
+ CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_GetContainer(decoder, length);
+ if (innerDecoder) {
+ success = subcontainerDecoder(innerDecoder, packetDictionary);
+ ccnxCodecTlvDecoder_Destroy(&innerDecoder);
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvUtilities_PutAsInteger(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int dictionaryKey)
+{
+ uint64_t value;
+ if (ccnxCodecTlvDecoder_GetVarInt(decoder, length, &value)) {
+ return ccnxTlvDictionary_PutInteger(packetDictionary, dictionaryKey, value);
+ }
+ return false;
+}
+
+bool
+ccnxCodecTlvUtilities_PutAsName(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int arrayKey)
+{
+ bool success = false;
+ CCNxName *name = ccnxCodecSchemaV1NameCodec_DecodeValue(decoder, length);
+ success = ccnxTlvDictionary_PutName(packetDictionary, arrayKey, name);
+ ccnxName_Release(&name);
+ return success;
+}
+
+bool
+ccnxCodecTlvUtilities_PutAsBuffer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int arrayKey)
+{
+ PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ bool success = ccnxTlvDictionary_PutBuffer(packetDictionary, arrayKey, buffer);
+ parcBuffer_Release(&buffer);
+ return success;
+}
+
+bool
+ccnxCodecTlvUtilities_PutAsHash(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int arrayKey)
+{
+ PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, length);
+ bool success = false;
+ if (hash != NULL) {
+ success = ccnxTlvDictionary_PutObject(packetDictionary, arrayKey, (const PARCObject *) hash);
+ parcCryptoHash_Release(&hash);
+ }
+ return success;
+}
+
+bool
+ccnxCodecTlvUtilities_PutAsListBuffer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int listKey)
+{
+ PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ bool success = ccnxTlvDictionary_PutListBuffer(packetDictionary, listKey, type, buffer);
+ parcBuffer_Release(&buffer);
+ return success;
+}
+
+ssize_t
+ccnxCodecTlvUtilities_NestedEncode(CCNxCodecTlvEncoder *outerEncoder, CCNxTlvDictionary *packetDictionary, uint32_t nestedType,
+ ssize_t (*nestedEncoderFunction)(CCNxCodecTlvEncoder *protoInfoEncoder, CCNxTlvDictionary *packetDictionary))
+{
+ size_t startPosition = ccnxCodecTlvEncoder_Position(outerEncoder);
+
+ ccnxCodecTlvEncoder_AppendContainer(outerEncoder, nestedType, 0);
+ ssize_t nestedLength = nestedEncoderFunction(outerEncoder, packetDictionary);
+ if (nestedLength > 0) {
+ ccnxCodecTlvEncoder_SetContainerLength(outerEncoder, startPosition, nestedLength);
+ } else {
+ // rewind the container
+ ccnxCodecTlvEncoder_SetPosition(outerEncoder, startPosition);
+ return nestedLength;
+ }
+
+ size_t endPosition = ccnxCodecTlvEncoder_Position(outerEncoder);
+ return endPosition - startPosition;
+}
+
+ssize_t
+ccnxCodecTlvUtilities_EncodeCustomList(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary, int listKey)
+{
+ ssize_t length = 0;
+
+ size_t size = ccnxTlvDictionary_ListSize(packetDictionary, listKey);
+ for (int i = 0; i < size; i++) {
+ PARCBuffer *buffer;
+ uint32_t key;
+
+ ssize_t innerLength = -1;
+ bool success = ccnxTlvDictionary_ListGetByPosition(packetDictionary, listKey, i, &buffer, &key);
+ if (success) {
+ innerLength = ccnxCodecTlvEncoder_AppendBuffer(encoder, key, buffer);
+ }
+
+ if (innerLength < 0) {
+ return -1;
+ }
+
+ length += innerLength;
+ }
+
+ return length;
+}
+
+bool
+ccnxCodecTlvUtilities_GetVarInt(PARCBuffer *input, size_t length, uint64_t *output)
+{
+ assertNotNull(input, "Parameter input must be non-null");
+ assertNotNull(output, "Parameter output must be non-null");
+
+ bool success = false;
+ if (length >= 1 && length <= 8 && parcBuffer_Remaining(input) >= length) {
+ uint64_t value = 0;
+ for (int i = 0; i < length; i++) {
+ value = value << 8 | parcBuffer_GetUint8(input);
+ }
+ *output = value;
+ success = true;
+ }
+ return success;
+}
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.h b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.h
new file mode 100644
index 00000000..81866701
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvUtilities.h
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodec_TlvUtilities.h
+ * @brief Utility functions common to all the codecs
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef TransportRTA_ccnxCodec_TlvUtilities_h
+#define TransportRTA_ccnxCodec_TlvUtilities_h
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+/**
+ * Decodes a list of TLV entries
+ *
+ * The decoder should point to the first byte of a "type". This function will iterate over all the TLVs
+ * and call the user function 'typeDecoder' for each type-length.
+ *
+ * It is the responsibility of typeDecoder to advance the decoder by 'length' bytes. It should return false
+ * if it does not consume exactly 'length' bytes.
+ *
+ * The function will proceed until it can no longer parse a TLV header (4 bytes). If the function consumes all
+ * the bytes in the decoder without error, it will return true. If it encounters an error from 'typeDecoder' it
+ * will return false at that point. If there is an underflow (i.e. 1, 2, or 3 bytes) left in the decoder at the end
+ * it will return false.
+ *
+ * @param [in] decoder The TLV decoder that should point to the start of the TLV list
+ * @param [in] packetDictionary The dictionary to use to store packet fields
+ * @param [in] typeDecoder the user-supplied function to call for each TLV found in the container
+ *
+ * @return true There were no errors returned by 'typeDecoder' and we consumed the entire decoder buffer
+ * @return false There was an error or we did not consume the entire decoder buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * static bool
+ * testTypeDecoder(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+ * {
+ * switch (type) {
+ * case 0x000C: // fallthrough
+ * case 0x000D:
+ * ccnxCodecTlvDecoder_Advance(decoder, length);
+ * return true;
+ * default:
+ * return false;
+ * }
+ * }
+ *
+ * void foo(void)
+ * {
+ * // A list of 2 TLV containers (types 0x000C and 0x000D)
+ * uint8_t metadataContainer[] = {
+ * 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1
+ * 0x04, // LINK
+ * 0x00, 0x0D, 0x00, 8, // Creation Time
+ * 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec
+ * 0x4B, 0x19, 0x84, 0x00,
+ * };
+ *
+ * PARCBuffer *buffer = parcBuffer_Wrap(metadataContainer, sizeof(metadataContainer), 0, sizeof(metadataContainer) );
+ *
+ * // now decode that snippit
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10,10);
+ *
+ * bool success = ccnxCodecTlvUtilities_DecodeContainer(decoder, dictionary, testTypeDecoder);
+ *
+ * ccnxTlvDictionary_Release(&dictionary);
+ * ccnxCodecTlvDecoder_Destroy(&decoder);
+ * parcBuffer_Release(&buffer);
+ *
+ * assertTrue(success, "The TLV types were known to us");
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvUtilities_DecodeContainer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, bool (*typeDecoder)(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length));
+
+/**
+ * Creates an inner decoder of for decoding a subcontainer
+ *
+ * The decoder should point at the first byte of the "value", which is known to be a subcontainer listing other
+ * TLVs. This function will create an inner decoder and then call 'ccnxCodecTlvUtilities_DecodeContainer' with it to
+ * decode the inner TLVs.
+ *
+ * @param [in] decoder The decoder that points to the fist byte of a list of TLVs.
+ * @param [in] packetDictionary Where to put the results
+ * @param [in] key NOT USED
+ * @param [in] length The length of the subcontainer. The inner decoder will end after this may bytes.
+ * @param [in] subcontainerDecoder The function to pass to 'ccnxCodecTlvUtilities_DecodeContainer' for the inner decoder
+ *
+ * @return true There were no errors and consumed 'length' bytes
+ * @return false An error or did not consume 'length' bytes
+ *
+ * Example:
+ * @code
+ * {
+ * // The KeyLocator field is known to be a subcontainer containing its own TLV fields. When we encounter that
+ * // TLV type, we parse the 'value' of it as a subcontainer
+ * //
+ * static bool
+ * rtaTlvSchemaV0NameAuth_DecodeType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+ * {
+ * bool success = false;
+ * switch (type) {
+ * case CCNxCodecSchemaV0_NameAuthKeys_KeyLocator:
+ * success = ccnxCodecTlvUtilities_DecodeSubcontainer(decoder, packetDictionary, type, length, rtaTlvSchemaV0KeyLocator_Decode);
+ * break;
+ *
+ * case CCNxCodecSchemaV0_NameAuthKeys_CryptoSuite:
+ * success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_CRYPTO_SUITE);
+ * break;
+ *
+ * case CCNxCodecSchemaV0_NameAuthKeys_KeyId:
+ * success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_KEYID);
+ * break;
+ *
+ * default:
+ * // if we do not know the TLV type, put it in this container's unknown list
+ * success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV0TlvDictionary_ContentObjectLists_NAMEAUTH_LIST);
+ * break;
+ * }
+ * return success;
+ * }
+ * @endcode
+ */
+bool
+ccnxCodecTlvUtilities_DecodeSubcontainer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t key, uint16_t length,
+ bool (*subcontainerDecoder)(CCNxCodecTlvDecoder *, CCNxTlvDictionary *));
+
+/**
+ * Decodes 'length' bytes from the decoder and puts it in the dictionary
+ *
+ * Reads the next 'length' bytes from the decoder and wraps it in a PARCBuffer. The buffer is saved in the packetDictionary
+ * under the key 'arrayKey'.
+ *
+ * It is an error if there are not 'length' bytes remaining in the decoder.
+ *
+ * @param [in] decoder The input to read
+ * @param [in] packetDictionary The output dictionary to save the buffer in
+ * @param [in] key The TLV key of the value being read (NOT USED)
+ * @param [in] length The byte length to read
+ * @param [in] dictionaryKey The key to use in the packetDictionary
+ *
+ * @return true 'length' bytes were read and saved in the packetDictionary
+ * @return false An error
+ *
+ * Example:
+ * @code
+ * {
+ * // A list of 2 TLV containers (types 0x000C and 0x000D)
+ * uint8_t metadataContainer[] = {
+ * 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1
+ * 0x04, // LINK
+ * 0x00, 0x0D, 0x00, 8, // Creation Time
+ * 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec
+ * 0x4B, 0x19, 0x84, 0x00,
+ * };
+ *
+ * PARCBuffer *buffer = parcBuffer_Wrap(metadataContainer, sizeof(metadataContainer), 0, sizeof(metadataContainer) );
+ *
+ * // now decode that snippit
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10,10);
+ *
+ * uint16_t tlvtype = ccnxCodecTlvDecoder_GetType(decoder);
+ * uint16_t tlvlength = ccnxCodecTlvDecoder_GetLength(decoder);
+ *
+ * // The buffer will contain the one byte 0x04.
+ * bool success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, dictionary, tlvtype, tlvlength, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_OBJ_TYPE);
+ *
+ * ccnxTlvDictionary_Release(&dictionary);
+ * ccnxCodecTlvDecoder_Destroy(&decoder);
+ * parcBuffer_Release(&buffer);
+ *
+ * assertTrue(success, "There was an unknown TLV at position %zu", ccnxCodecTlvDecoder_Position(decoder));
+ * }
+ * @endcode
+ */
+bool
+ccnxCodecTlvUtilities_PutAsBuffer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int dictionaryKey);
+
+/**
+ * Decodes a `PARCCryptoHash` value of 'length' bytes from the decoder and puts it in the dictionary.
+ *
+ * It is an error if there are not 'length' bytes remaining in the decoder.
+ *
+ * @param [in] decoder The input to read
+ * @param [in] packetDictionary The output dictionary to save the buffer in
+ * @param [in] key The TLV key of the value being read (NOT USED)
+ * @param [in] length The byte length to read
+ * @param [in] dictionaryKey The key to use in the packetDictionary
+ *
+ * @return true 'length' bytes were read and saved in the packetDictionary
+ * @return false An error
+ *
+ * Example:
+ * @code
+ * {
+ * // A list of 2 TLV containers (types 0x000C and 0x000D)
+ * uint8_t hashContainer[] = {
+ * 0x00, 0x01, 0x00, 0x20, // SHA256 hash, length = 0x20
+ * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ * };
+ *
+ * PARCBuffer *buffer = parcBuffer_Wrap(hashContainer, sizeof(hashContainer), 0, sizeof(hashContainer) );
+ *
+ * // now decode that snippit
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10,10);
+ *
+ * uint16_t tlvtype = ccnxCodecTlvDecoder_GetType(decoder);
+ * uint16_t tlvlength = ccnxCodecTlvDecoder_GetLength(decoder);
+ *
+ * bool success = ccnxCodecTlvUtilities_PutAsHash(decoder, dictionary, tlvtype, tlvlength, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION);
+ *
+ * ccnxTlvDictionary_Release(&dictionary);
+ * ccnxCodecTlvDecoder_Destroy(&decoder);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+bool
+ccnxCodecTlvUtilities_PutAsHash(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int dictionaryKey);
+
+/**
+ * Decodes the value as a VarInt and saves it as an Integer in the Dictionary
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool
+ccnxCodecTlvUtilities_PutAsInteger(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int dictionaryKey);
+
+
+/**
+ * Decodes 'length' bytes from the decoder and puts it in the dictionary as a CCNxName
+ *
+ * Reads the next 'length' bytes from the decoder and wraps it in a CCNxName. The name is saved in the packetDictionary
+ * under the key 'arrayKey'.
+ *
+ * It is an error if there are not 'length' bytes remaining in the decoder.
+ *
+ * @param [in] decoder The input to read
+ * @param [in] packetDictionary The output dictionary to save the name in
+ * @param [in] key The TLV key of the value being read (NOT USED)
+ * @param [in] length The byte length to read
+ * @param [in] dictionaryKey The key to use in the packetDictionary
+ *
+ * @return true 'length' bytes were read and saved in the packetDictionary
+ * @return false An error
+ *
+ * Example:
+ * @code
+ * {
+ * // A list of 2 TLV containers (types 0x000C and 0x000D)
+ * uint8_t metadataContainer[] = {
+ * 0x00, 0x00, 0x00, 9, // type = name, length = 9
+ * 0x00, 0x02, 0x00, 5, // type = binary, length = 5
+ * 'h', 'e', 'l', 'l', // "hello"
+ * 'o',
+ * };
+ *
+ * PARCBuffer *buffer = parcBuffer_Wrap(metadataContainer, sizeof(metadataContainer), 0, sizeof(metadataContainer) );
+ *
+ * // now decode that snippit
+ * CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ * CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10,10);
+ *
+ * uint16_t tlvtype = ccnxCodecTlvDecoder_GetType(decoder);
+ * uint16_t tlvlength = ccnxCodecTlvDecoder_GetLength(decoder);
+ *
+ * // Saves "lci:/hello"
+ * bool success = ccnxCodecTlvUtilities_PutAsName(decoder, dictionary, tlvtype, tlvlength, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_NAME);
+ *
+ * ccnxTlvDictionary_Release(&dictionary);
+ * ccnxCodecTlvDecoder_Destroy(&decoder);
+ * parcBuffer_Release(&buffer);
+ *
+ * assertTrue(success, "The Name failed to decode or some other error");
+ * }
+ * @endcode
+ */
+bool
+ccnxCodecTlvUtilities_PutAsName(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int arrayKey);
+
+/**
+ * Reads 'length' bytes from the decoder and appends a PARCBuffer to a list in packetDictionary
+ *
+ * Saves a buffer as part of a List in the packet dictionary. This is primarily used for unknown TLV types that
+ * do not have a specific decoder.
+ *
+ * @param [in] decoder The decoder to read
+ * @param [in] packetDictionary The dictionary to append the buffer in
+ * @param [in] type The TLV type of the buffer (saved as part of the list entry)
+ * @param [in] length The length to wrap in the buffer
+ * @param [in] listKey The list key in packetDictionary
+ *
+ * @return true Success
+ * @return false Failure or error
+ *
+ * Example:
+ * @code
+ * {
+ * // If we exhaust all the known keys in the Name Authenticator, the default case will save the TLV in
+ * // the container's list in the packet dictionary.
+ * //
+ * static bool
+ * rtaTlvSchemaV0NameAuth_DecodeType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+ * {
+ * bool success = false;
+ * switch (type) {
+ * case CCNxCodecSchemaV0_NameAuthKeys_KeyLocator:
+ * success = ccnxCodecTlvUtilities_DecodeSubcontainer(decoder, packetDictionary, type, length, rtaTlvSchemaV0KeyLocator_Decode);
+ * break;
+ *
+ * case CCNxCodecSchemaV0_NameAuthKeys_CryptoSuite:
+ * success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_CRYPTO_SUITE);
+ * break;
+ *
+ * case CCNxCodecSchemaV0_NameAuthKeys_KeyId:
+ * success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_KEYID);
+ * break;
+ *
+ * default:
+ * // if we do not know the TLV type, put it in this container's unknown list
+ * success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV0TlvDictionary_ContentObjectLists_NAMEAUTH_LIST);
+ * break;
+ * }
+ * return success;
+ * }
+ * @endcode
+ */
+bool
+ccnxCodecTlvUtilities_PutAsListBuffer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length, int listKey);
+
+/**
+ * Encodes a nested TLV container (the opposite of ccnxCodecTlvUtilities_DecodeSubcontainer)
+ *
+ * Appends a TLV header (4 bytes) to the encoder using 'nestedType' as the TLV type. It then calls 'nestedEncoderFunction' to
+ * encode the 'value' of the container. If 'nestedEncoderFunction' returns positive bytes it will go back and fill in the proper TLV length.
+ * If 'nestedEncoderFunction' returns 0 or negative bytes, it rewinds the encoder to the original position before appending the TLV header.
+ *
+ * @param [in] outerEncoder The encoder to append to
+ * @param [in] packetDictionary The dictionary to read from
+ * @param [in] nestedType the TLV type to use for the nested value
+ * @param [in] nestedEncoderFunction The function to call to write the inner value
+ *
+ * @return non-negative The total number of bytes appended to 'outerEncoder'
+ * @return -1 An error
+ *
+ * Example:
+ * @code
+ * {
+ * // If the dictionary contains a KeyName Name, then encode the KeyName continer using 'rtaTlvSchemaV0KeyName_Encode'. Use
+ * // the value 'CCNxCodecSchemaV0_KeyLocatorKeys_KeyName' as the TLV type for the subcontainer.
+ * //
+ * if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV0TlvDictionary_ContentObjectFastArray_KEYNAME_NAME)) {
+ * keynameLength = ccnxCodecTlvUtilities_NestedEncode(keyLocatorEncoder, packetDictionary, CCNxCodecSchemaV0_KeyLocatorKeys_KeyName, rtaTlvSchemaV0KeyName_Encode);
+ * }
+ * }
+ * @endcode
+ */
+ssize_t
+ccnxCodecTlvUtilities_NestedEncode(CCNxCodecTlvEncoder *outerEncoder, CCNxTlvDictionary *packetDictionary, uint32_t nestedType,
+ ssize_t (*nestedEncoderFunction)(CCNxCodecTlvEncoder *innerEncoder, CCNxTlvDictionary *packetDictionary));
+
+/**
+ * Reads the list 'listKey' from the dictionary and encodes them all as TLV entries
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] encoder The encoder to append to
+ * @param [in] packetDictionary The dictionary to read from
+ * @param [in] listKey The list key to read from packetDictionary
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t
+ccnxCodecTlvUtilities_EncodeCustomList(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary, int listKey);
+
+
+/**
+ * Parses the input buffer as a VarInt
+ *
+ * Parses the bytes of the input buffer as a network byte order variable length integer.
+ * Between 1 and 'length' bytes will be parses, where 'length' must be from 1 to 8.
+ * The buffer will be advanced as the bytes are read.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00 }, 3, 0, 3 );
+ * uint64_t value;
+ * ccnxCodecTlvUtilities_GetVarInt(buffer, 3, &value);
+ * // value = 0x0000000000102300
+ * }
+ * @endcode
+ */
+bool ccnxCodecTlvUtilities_GetVarInt(PARCBuffer *input, size_t length, uint64_t *output);
+
+#endif // TransportRTA_ccnxCodec_TlvUtilities_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.c
new file mode 100755
index 00000000..588694b0
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h>
+
+
+bool
+ccnxCodecSchemaV1CryptoSuite_ParcToTlv(PARCCryptoSuite parcSuite, CCNxCodecSchemaV1TlvDictionary_CryptoSuite *outputValue)
+{
+ bool matchFound = false;
+ switch (parcSuite) {
+ case PARCCryptoSuite_RSA_SHA256:
+ *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256;
+ matchFound = true;
+ break;
+
+ case PARCCryptoSuite_DSA_SHA256:
+ // not supported yet
+ break;
+
+ case PARCCryptoSuite_RSA_SHA512:
+ // not supported yet
+ break;
+
+ case PARCCryptoSuite_HMAC_SHA256:
+ *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256;
+ matchFound = true;
+ break;
+
+ case PARCCryptoSuite_HMAC_SHA512:
+ // not supported yet
+ break;
+
+ case PARCCryptoSuite_NULL_CRC32C:
+ *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C;
+ matchFound = true;
+ break;
+
+ default:
+ // unknown
+ break;
+ }
+ return matchFound;
+}
+
+bool
+ccnxCodecSchemaV1CryptoSuite_TlvToParc(CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvValue, PARCCryptoSuite *outputSuite)
+{
+ bool matchFound = false;
+ switch (tlvValue) {
+ case CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256:
+ *outputSuite = PARCCryptoSuite_RSA_SHA256;
+ matchFound = true;
+ break;
+
+ case CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C:
+ *outputSuite = PARCCryptoSuite_NULL_CRC32C;
+ matchFound = true;
+ break;
+
+ case CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256:
+ *outputSuite = PARCCryptoSuite_HMAC_SHA256;
+ matchFound = true;
+ break;
+
+ case CCNxCodecSchemaV1TlvDictionary_CryptoSuite_EcSecp256K1:
+ // not supported yet
+ break;
+
+ default:
+ // unknown
+ break;
+ }
+ return matchFound;
+}
+
+bool
+ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv(PARCSigningAlgorithm signAlgorithm, PARCCryptoHashType hashType, CCNxCodecSchemaV1TlvDictionary_CryptoSuite *outputValue)
+{
+ bool matchFound = false;
+ switch (signAlgorithm) {
+ case PARCSigningAlgorithm_RSA: {
+ switch (hashType) {
+ case PARCCryptoHashType_SHA256:
+ *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256;
+ matchFound = true;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ case PARCSigningAlgorithm_HMAC: {
+ switch (hashType) {
+ case PARCCryptoHashType_SHA256:
+ *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256;
+ matchFound = true;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case PARCSigningAlgortihm_NULL: {
+ switch (hashType) {
+ case PARCCryptoHashType_CRC32C:
+ *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C;
+ matchFound = true;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return matchFound;
+}
+
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h
new file mode 100755
index 00000000..68e90749
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_CryptoSuite.h
+ * @brief Translates between PARC CryptoSuite values and the wire encoding
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#include <stdbool.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_SigningAlgorithm.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+/**
+ * Converts a PARC Crypto Suite to its TLV value
+ *
+ * Looks up the PARC cryptosuite value and returns the corresponding TLV wire format value.
+ * If no match is found, returns false and outputSuite is not modified.
+ *
+ *
+ * @param [in] parcSuite The PARC cryptosuite
+ * @param [out] outputValue The wire encoding equivalent
+ *
+ * @retval true if supported suite and outputValue set.
+ * @retval false if not supported.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1CryptoSuite_ParcToTlv(PARCCryptoSuite parcSuite, CCNxCodecSchemaV1TlvDictionary_CryptoSuite *outputValue);
+
+/**
+ * Converts a wire format cryptosuite value to the PARC cryptosuite
+ *
+ * Looks up the TLV wire format value and returns the corresponding PARC cryptosuite.
+ * If no match is found, returns false and outputSuite is not modified.
+ *
+ * @param [in] tlvValue The wire format value
+ * @param [out] outputValue The PARC equivalent
+ *
+ * @return true if match found and parcSuite set.
+ * @return false if no match found.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1CryptoSuite_TlvToParc(CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvValue, PARCCryptoSuite *outputSuite);
+
+/**
+ * Lookup a signing algorithm and hash type and convert to a wire format value
+ *
+ * Based on a PARCSigner's algorithm and hash type, find the corresponding wire format crypto suite.
+ *
+ * @param [in] signAlgorithm The signing algorithm
+ * @param [in] hashType The hash used by the signing algorithm
+ * @param [out] outputValue The wire format value
+ *
+ * @retval true if supported suite and outputValue set.
+ * @retval false if not supported.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv(PARCSigningAlgorithm signAlgorithm, PARCCryptoHashType hashType, CCNxCodecSchemaV1TlvDictionary_CryptoSuite *outputValue);
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h
new file mode 100755
index 00000000..3055c054
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_FixedHeader.h
+ * @brief common definitions and functions for the FixedHeader
+ *
+ * See ccnxCodecSchemaV1_Packet.h for an overview of the version 1 codec
+ *
+ * This is the one file you need to include for all FixedHeader operations. It will
+ * include all the Decoders and Encoders.
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_FixedHeader_h
+#define TransportRTA_ccnxCodecSchemaV1_FixedHeader_h
+
+typedef struct __attribute__ ((__packed__)) rta_tlv_schema_v1_fixed_header {
+ uint8_t version;
+ uint8_t packetType;
+ uint16_t packetLength;
+ uint8_t reserved[3];
+ uint8_t headerLength;
+} CCNxCodecSchemaV1FixedHeader;
+
+typedef struct __attribute__ ((__packed__)) rta_tlv_schema_v1_interest_header {
+ uint8_t version;
+ uint8_t packetType;
+ uint16_t packetLength;
+ uint8_t hopLimit;
+ uint8_t returnCode;
+ uint8_t flags;
+ uint8_t headerLength;
+} CCNxCodecSchemaV1InterestHeader;
+
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h>
+#endif // TransportRTA_ccnxCodecSchemaV1_FixedHeader_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.c
new file mode 100755
index 00000000..fcec49b3
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+static const size_t _fixedHeaderBytes = 8;
+
+static const int _fixedHeader_VersionOffset = 0;
+static const int _fixedHeader_PacketTypeOffset = 1;
+static const int _fixedHeader_PacketLengthOffset = 2;
+static const int _fixedHeader_HopLimitOffset = 4;
+static const int _fixedHeader_ReturnCodeOffset = 5;
+static const int _fixedHeader_FlagsOffset = 6;
+static const int _fixedHeader_HeaderLengthOffset = 7;
+
+bool
+ccnxCodecSchemaV1FixedHeaderDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, _fixedHeaderBytes)) {
+ PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, _fixedHeaderBytes);
+ bool success = ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader, buffer);
+
+ // validation
+ parcBuffer_SetPosition(buffer, _fixedHeader_VersionOffset);
+ uint8_t version = parcBuffer_GetUint8(buffer);
+
+ parcBuffer_SetPosition(buffer, _fixedHeader_PacketLengthOffset);
+ uint16_t packetLength = parcBuffer_GetUint16(buffer);
+
+ parcBuffer_SetPosition(buffer, _fixedHeader_ReturnCodeOffset);
+ uint8_t interestReturnCode = parcBuffer_GetUint8(buffer);
+
+ parcBuffer_SetPosition(buffer, _fixedHeader_HopLimitOffset);
+ uint8_t hopLimit = parcBuffer_GetUint8(buffer);
+
+ parcBuffer_SetPosition(buffer, _fixedHeader_HeaderLengthOffset);
+ uint8_t headerLength = parcBuffer_GetUint8(buffer);
+
+ if (version != 1) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_VERSION, __func__, __LINE__, _fixedHeader_VersionOffset);
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ success = false;
+ } else if (packetLength < _fixedHeaderBytes) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETLENGTH_TOO_SHORT, __func__, __LINE__, _fixedHeader_PacketTypeOffset);
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ success = false;
+ } else if (headerLength < _fixedHeaderBytes) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_HEADERLENGTH_TOO_SHORT, __func__, __LINE__, _fixedHeader_HeaderLengthOffset);
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ success = false;
+ } else if (packetLength < headerLength) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETLENGTHSHORTER, __func__, __LINE__, _fixedHeader_PacketTypeOffset);
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ success = false;
+ }
+
+ // decoder now points to just past the fixed header
+ parcBuffer_Release(&buffer);
+
+ // Set the hoplimit in the dictionary.
+ ccnxTlvDictionary_PutInteger(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, hopLimit);
+
+ // Set the InterestReturn code in the dictionary.
+ ccnxTlvDictionary_PutInteger(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode,
+ interestReturnCode);
+
+ return success;
+ } else {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ return false;
+ }
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_VersionOffset);
+ uint8_t version = parcBuffer_GetUint8(fixedHeader);
+ return version;
+ }
+
+ return -1;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_PacketTypeOffset);
+ uint8_t packetType = parcBuffer_GetUint8(fixedHeader);
+ return packetType;
+ }
+
+ return -1;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_PacketLengthOffset);
+ uint16_t payloadLength = parcBuffer_GetUint16(fixedHeader);
+ return payloadLength;
+ }
+
+ return -1;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(CCNxTlvDictionary *packetDictionary)
+{
+ int length = -1;
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_HeaderLengthOffset);
+ uint8_t headerLength = parcBuffer_GetUint8(fixedHeader);
+
+ // 8 is the minimum size of headerLength
+ if (headerLength >= _fixedHeaderBytes) {
+ length = headerLength;
+ }
+ }
+
+ return length;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetOptionalHeaderLength(CCNxTlvDictionary *packetDictionary)
+{
+ int headerLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(packetDictionary);
+ return headerLength - _fixedHeaderBytes;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_HopLimitOffset);
+ uint8_t hopLimit = parcBuffer_GetUint8(fixedHeader);
+ return hopLimit;
+ }
+
+ return -1;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_ReturnCodeOffset);
+ uint8_t returnCode = parcBuffer_GetUint8(fixedHeader);
+ return returnCode;
+ }
+
+ return -1;
+}
+
+int
+ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+ if (fixedHeader != NULL) {
+ parcBuffer_SetPosition(fixedHeader, _fixedHeader_FlagsOffset);
+ uint8_t flags = parcBuffer_GetUint8(fixedHeader);
+ return flags;
+ }
+
+ return -1;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h
new file mode 100755
index 00000000..5d15f40b
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#ifndef Libccnx_ccnxCodecSchemaV1_FixedHeaderDecoder_h
+#define Libccnx_ccnxCodecSchemaV1_FixedHeaderDecoder_h
+
+#include <stdbool.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+/**
+ * The decode a V1 fixed header
+ *
+ * The decoder should point to byte 0 of the Fixed Header.
+ * It will be advanced to the first byte following it.
+ * The results are put in the provided.
+ *
+ * @param [in] decoder The decoder to parse
+ * @param [in] dictionary The results go directly in to the provided dictionary.
+ *
+ * @return true Fully parsed interest, no errors
+ * @return false Error decoding, decoder is left pointing to the first byte of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1FixedHeaderDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the version
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @return positive The Version
+ * @return -1 The field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the PacketType
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @return positive The PacketType
+ * @return -1 The field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the PacketLength
+ *
+ * The PacketLength is measured from byte 0 to the end of the packet
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @return positive The packet length (in host byte order)
+ * @return -1 The field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the HeaderLength
+ *
+ * In a version 1 packet, the header length includes the fixed header. It is measured from
+ * byte 0 to the end of the hop-by-hop headers.
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @return positive The header length
+ * @return -1 The field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * Returns the bytes of the optional headers
+ *
+ * Computes ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength() - sizeof(fixedHeader)
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @retval non-negative The length of the optional headers
+ * @retval negative An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetOptionalHeaderLength(CCNxTlvDictionary *packetDictionary);
+
+
+/**
+ * A convenience function to return the ReturnCode of an Interest or InterestReturn
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @return positive The Return Code
+ * @return -1 The field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the header Flags
+ *
+ * @param [in] fixedHeaderDictionary The FixedHeader dictionary
+ *
+ * @return positive The flags
+ * @return -1 The field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags(CCNxTlvDictionary *packetDictionary);
+
+#endif // Libccnx_ccnxCodecSchemaV1_FixedHeaderDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.c
new file mode 100755
index 00000000..3b6eca67
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+ssize_t
+ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(CCNxCodecTlvEncoder *fixedHeaderEncoder, const CCNxCodecSchemaV1FixedHeader *header)
+{
+ assertNotNull(fixedHeaderEncoder, "Parameter fixedHeaderEncoder must be non-null");
+ assertNotNull(header, "Parameter header must be non-null");
+ trapIllegalValueIf(header->version != 1, "Header wrong version, must be 1");
+
+ CCNxCodecSchemaV1InterestHeader copy;
+
+ memcpy(&copy, header, sizeof(CCNxCodecSchemaV1InterestHeader));
+
+ copy.packetLength = htons(header->packetLength);
+
+ switch (header->packetType) {
+ case CCNxCodecSchemaV1Types_PacketType_Interest:
+ copy.returnCode = 0;
+ break;
+
+ case CCNxCodecSchemaV1Types_PacketType_InterestReturn:
+ // nothing to do, all fields used
+ break;
+
+ default:
+ copy.hopLimit = 0;
+ copy.returnCode = 0;
+ copy.flags = 0;
+ break;
+ }
+
+ ccnxCodecTlvEncoder_AppendRawArray(fixedHeaderEncoder, sizeof(CCNxCodecSchemaV1FixedHeader), (uint8_t *) &copy);
+ return sizeof(CCNxCodecSchemaV1FixedHeader);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h
new file mode 100755
index 00000000..0981f4bd
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_FixedHeaderEncoder.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef Libccnx_ccnxCodecSchemaV1_FixedHeaderEncoder_h
+#define Libccnx_ccnxCodecSchemaV1_FixedHeaderEncoder_h
+
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+
+/**
+ * Set the values in the fixed header
+ *
+ * Put the provided fixed header at the given byte location. The provided fixed header is not put
+ * in as-is (i.e byte for byte), but is parsed and put in the correct byte positions and encodings
+ * assuming the fixed header starts at the given position.
+ *
+ * The encoder is returned to its current position after putting the header.
+ *
+ * @param [in] encoder The encoder to append the fixed header in to
+ * @param [in] The header, in host byte order
+ *
+ * @return Number The bytes appended, or -1 on error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(CCNxCodecTlvEncoder *encoder, const CCNxCodecSchemaV1FixedHeader *header);
+#endif // Libccnx_ccnxCodecSchemaV1_FixedHeaderEncoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c
new file mode 100644
index 00000000..23a559cc
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h>
+
+/**
+ * These are the accepted sizes for the pre-defined hash types.
+ * Hash TLVs with lengths that do not match one of these values will be deemed
+ * invalid and not parse correctly.
+ */
+static const size_t _PARCCryptoHashType_SHA256_Sizes[] = { 32 };
+static const size_t _PARCCryptoHashType_SHA512_Sizes[] = { 32, 64 };
+
+static bool
+_ccnxCodecSchemaV1HashCodec_ValidHashSize(size_t size, size_t numSizes, size_t sizes[numSizes])
+{
+ for (size_t i = 0; i < numSizes; i++) {
+ if (sizes[i] == size) {
+ return true;
+ }
+ }
+ return false;
+}
+
+ssize_t
+ccnxCodecSchemaV1HashCodec_Encode(CCNxCodecTlvEncoder *encoder, const PARCCryptoHash *hash)
+{
+ PARCBuffer *digest = parcCryptoHash_GetDigest(hash);
+ PARCCryptoHashType hashType = parcCryptoHash_GetDigestType(hash);
+ size_t digestLength = parcBuffer_Remaining(digest);
+
+ uint16_t tlvHashType = CCNxCodecSchemaV1Types_HashType_App;
+ bool validHash = true;
+ switch (hashType) {
+ case PARCCryptoHashType_SHA256:
+ tlvHashType = CCNxCodecSchemaV1Types_HashType_SHA256;
+ validHash = _ccnxCodecSchemaV1HashCodec_ValidHashSize(digestLength,
+ sizeof(_PARCCryptoHashType_SHA256_Sizes) / sizeof(size_t), (size_t *) _PARCCryptoHashType_SHA256_Sizes);
+ break;
+ case PARCCryptoHashType_SHA512:
+ tlvHashType = CCNxCodecSchemaV1Types_HashType_SHA512;
+ validHash = _ccnxCodecSchemaV1HashCodec_ValidHashSize(digestLength,
+ sizeof(_PARCCryptoHashType_SHA512_Sizes) / sizeof(size_t), (size_t *) _PARCCryptoHashType_SHA512_Sizes);
+ break;
+ default:
+ break;
+ }
+
+ if (validHash) {
+ return ccnxCodecTlvEncoder_AppendBuffer(encoder, tlvHashType, digest);
+ } else {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder));
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+
+ return -1;
+ }
+}
+
+static bool
+_ccnxCodecSchemaV1HashCodec_ValidHash(uint16_t hashType, uint16_t hashSize)
+{
+ bool validHash = true;
+
+ switch (hashType) {
+ case CCNxCodecSchemaV1Types_HashType_SHA256:
+ validHash = _ccnxCodecSchemaV1HashCodec_ValidHashSize(hashSize,
+ sizeof(_PARCCryptoHashType_SHA256_Sizes) / sizeof(size_t), (size_t *) _PARCCryptoHashType_SHA256_Sizes);
+ break;
+ case CCNxCodecSchemaV1Types_HashType_SHA512:
+ validHash = _ccnxCodecSchemaV1HashCodec_ValidHashSize(hashSize,
+ sizeof(_PARCCryptoHashType_SHA512_Sizes) / sizeof(size_t), (size_t *) _PARCCryptoHashType_SHA512_Sizes);
+ break;
+ default:
+ break;
+ }
+
+ return validHash;
+}
+
+PARCCryptoHash *
+ccnxCodecSchemaV1HashCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, size_t limit)
+{
+ PARCCryptoHash *hash = NULL;
+ uint16_t hashType = 0;
+ uint16_t length = 0;
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) {
+ hashType = ccnxCodecTlvDecoder_GetType(decoder);
+ length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ if (length > limit) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ return NULL;
+ }
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) {
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ switch (hashType) {
+ case CCNxCodecSchemaV1Types_HashType_SHA256:
+ hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, value);
+ break;
+ case CCNxCodecSchemaV1Types_HashType_SHA512:
+ hash = parcCryptoHash_Create(PARCCryptoHashType_SHA512, value);
+ break;
+ case CCNxCodecSchemaV1Types_HashType_App:
+ hash = parcCryptoHash_Create(PARCCryptoHashType_NULL, value);
+ break;
+ }
+ parcBuffer_Release(&value);
+ }
+ }
+
+ // Verify the hash size, if one was parsed correctly.
+ if (hash != NULL && !_ccnxCodecSchemaV1HashCodec_ValidHash(hashType, length)) {
+ parcCryptoHash_Release(&hash);
+ }
+
+ return hash;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h
new file mode 100755
index 00000000..f03b3746
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_HashCodec.h
+ * @brief A cryptographic hash digest encoded
+ *
+ */
+
+#ifndef __CCNx_Common__ccnxCodecSchemaV1_HashCodec__
+#define __CCNx_Common__ccnxCodecSchemaV1_HashCodec__
+
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+#include <parc/security/parc_CryptoHash.h>
+
+/**
+ * Encodes the hash, but without a "TL" container
+ *
+ * Will append the Link in it's well-known TLV format, but without any
+ * "TL" container.
+ *
+ * If the link does not have a name, will return -1 with the error TLV_MISSING_MANDATORY.
+ *
+ * @param [in] encoder The hash will be appended to the encoder
+ * @param [in] hash The hash to append
+ *
+ * @retval non-negative The number of bytes appended to the encoder
+ * @retval negative An error, look at the CCNxCodecError of the encoder
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1HashCodec_Encode(CCNxCodecTlvEncoder *encoder, const PARCCryptoHash *hash);
+
+/**
+ * The decoder points to the first byte of the "value" of something that is a Link
+ *
+ * For a KeyName, decoder should be pointed to the "value" of the KeyName. for a ContentObject
+ * of type Link, it should be the first byte of the Payload.
+ *
+ * A link is the tuple {Name, [KeyId], [Hash]}, where KeyId is the keyIdRestriction and
+ * Hash is the ContentObjectHash restriction to use in an Interest for Name.
+ * No additional fields are allowed in the Link.
+ *
+ * @param [in] decoder The Tlv Decoder pointing to the start of the Name value
+ * @param [in] length the length of the Hash value
+ *
+ * @return non-null A parsed name
+ * @return null An error, check the decoder's error message
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCCryptoHash *ccnxCodecSchemaV1HashCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, size_t length);
+
+#endif // __CCNx_Common__ccnxCodecSchemaV1_HashCodec__
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c
new file mode 100755
index 00000000..cc78c28e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h>
+
+ssize_t
+ccnxCodecSchemaV1LinkCodec_Encode(CCNxCodecTlvEncoder *encoder, const CCNxLink *link)
+{
+ ssize_t length = 0;
+
+ const CCNxName *name = ccnxLink_GetName(link);
+ if (name) {
+ length += ccnxCodecSchemaV1NameCodec_Encode(encoder, CCNxCodecSchemaV1Types_Link_Name, name);
+
+ PARCBuffer *keyid = ccnxLink_GetKeyID(link);
+ if (keyid) {
+ length += ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_Link_KeyIdRestriction, keyid);
+ }
+
+ PARCBuffer *hash = ccnxLink_GetContentObjectHash(link);
+ if (hash) {
+ length += ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_Link_ContentObjectHashRestriction, hash);
+ }
+ } else {
+ length = -1;
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder));
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+ }
+
+ return length;
+}
+
+typedef struct decoded_link {
+ CCNxName *linkName;
+ PARCBuffer *linkKeyId;
+ PARCBuffer *linkHash;
+} _DecodedLink;
+
+static int
+_decodeField(CCNxCodecTlvDecoder *decoder, _DecodedLink *decodedLink)
+{
+ int errorCode = TLV_ERR_NO_ERROR;
+
+ uint16_t type = ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) {
+ switch (type) {
+ case CCNxCodecSchemaV1Types_Link_Name:
+ if (decodedLink->linkName == NULL) {
+ decodedLink->linkName = ccnxCodecSchemaV1NameCodec_DecodeValue(decoder, length);
+ } else {
+ errorCode = TLV_ERR_DUPLICATE_FIELD;
+ }
+ break;
+
+ case CCNxCodecSchemaV1Types_Link_KeyIdRestriction:
+ if (decodedLink->linkKeyId == NULL) {
+ decodedLink->linkKeyId = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ } else {
+ errorCode = TLV_ERR_DUPLICATE_FIELD;
+ }
+ break;
+
+ case CCNxCodecSchemaV1Types_Link_ContentObjectHashRestriction:
+ if (decodedLink->linkHash == NULL) {
+ decodedLink->linkHash = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ } else {
+ errorCode = TLV_ERR_DUPLICATE_FIELD;
+ }
+ break;
+
+ default:
+ // we do not support unknown TLVs
+ errorCode = TLV_ERR_DECODE;
+ break;
+ }
+ } else {
+ errorCode = TLV_ERR_TOO_LONG;
+ }
+
+ return errorCode;
+}
+
+static void
+_decodecLinkCleanup(_DecodedLink *decodedLink)
+{
+ if (decodedLink->linkName) {
+ ccnxName_Release(&decodedLink->linkName);
+ }
+
+ if (decodedLink->linkKeyId) {
+ parcBuffer_Release(&decodedLink->linkKeyId);
+ }
+
+ if (decodedLink->linkHash) {
+ parcBuffer_Release(&decodedLink->linkHash);
+ }
+}
+
+CCNxLink *
+ccnxCodecSchemaV1LinkCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, uint16_t linkLength)
+{
+ int errorCode = TLV_ERR_NO_ERROR;
+
+ CCNxLink *link = NULL;
+
+ _DecodedLink decodedLink;
+ memset(&decodedLink, 0, sizeof(_DecodedLink));
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, linkLength)) {
+ while (errorCode == TLV_ERR_NO_ERROR && ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) {
+ errorCode = _decodeField(decoder, &decodedLink);
+ }
+ } else {
+ errorCode = TLV_ERR_TOO_LONG;
+ }
+
+ if (errorCode == TLV_ERR_NO_ERROR && decodedLink.linkName == NULL) {
+ errorCode = TLV_ERR_DECODE;
+ }
+
+ if (errorCode != TLV_ERR_NO_ERROR) {
+ CCNxCodecError *error = ccnxCodecError_Create(errorCode, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ } else {
+ link = ccnxLink_Create(decodedLink.linkName, decodedLink.linkKeyId, decodedLink.linkHash);
+ }
+
+ // cleanup any partial memory allocations
+ _decodecLinkCleanup(&decodedLink);
+
+ return link;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h
new file mode 100755
index 00000000..4163aa1d
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_LinkCodec.h
+ * @brief A Link is a well-known value, not a TLV field
+ *
+ * A Link may be the "value" of a TLV element, such as the KeyName. It can also occur
+ * in the payload of a ContentObject whose PayloadType is Link.
+ *
+ */
+
+#ifndef __CCNx_Common__ccnxCodecSchemaV1_LinkCodec__
+#define __CCNx_Common__ccnxCodecSchemaV1_LinkCodec__
+
+#include <ccnx/common/ccnx_Link.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+/**
+ * Encodes the link, but without a "TL" container
+ *
+ * Will append the Link in it's well-known TLV format, but without any
+ * "TL" container.
+ *
+ * If the link does not have a name, will return -1 with the error TLV_MISSING_MANDATORY.
+ *
+ * @param [in] encoder The link will be appended to the encoder
+ * @param [in] link The link to append
+ *
+ * @retval non-negative The number of bytes appended to the encoder
+ * @retval negative An error, look at the CCNxCodecError of the encoder
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1LinkCodec_Encode(CCNxCodecTlvEncoder *encoder, const CCNxLink *link);
+
+/**
+ * The decoder points to the first byte of the "value" of something that is a Link
+ *
+ * For a KeyName, decoder should be pointed to the "value" of the KeyName. for a ContentObject
+ * of type Link, it should be the first byte of the Payload.
+ *
+ * A link is the tuple {Name, [KeyId], [Hash]}, where KeyId is the keyIdRestriction and
+ * Hash is the ContentObjectHash restriction to use in an Interest for Name.
+ * No additional fields are allowed in the Link.
+ *
+ * @param [in] decoder The Tlv Decoder pointing to the start of the Name value
+ * @param [in] length the length of the Link value
+ *
+ * @return non-null A parsed name
+ * @return null An error, check the decoder's error message
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxLink *ccnxCodecSchemaV1LinkCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, uint16_t length);
+
+#endif /* defined(__CCNx_Common__ccnxCodecSchemaV1_LinkCodec__) */
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c
new file mode 100644
index 00000000..87665de1
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <ccnx/common/ccnx_PayloadType.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+#include <ccnx/common/ccnx_Manifest.h>
+#include <ccnx/common/ccnx_ManifestHashGroup.h>
+
+static bool
+_decodeHashGroupMetadata(CCNxCodecTlvDecoder *decoder, CCNxManifestHashGroup *group, size_t length)
+{
+ size_t offset = 0;
+ bool success = true;
+
+ while (offset < length) {
+ uint16_t type = ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t value_length = ccnxCodecTlvDecoder_GetLength(decoder);
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(decoder, value_length);
+
+ offset += (4 + value_length);
+
+ switch (type) {
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator: {
+ char *nameString = parcBuffer_ToString(value);
+ const CCNxName *locator = ccnxName_CreateFromCString(nameString);
+ ccnxManifestHashGroup_SetLocator(group, locator);
+ parcMemory_Deallocate(&nameString);
+ ccnxName_Release((CCNxName **) &locator);
+ break;
+ }
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize: {
+ uint64_t dataSize = parcBuffer_GetUint64(value);
+ ccnxManifestHashGroup_SetDataSize(group, dataSize);
+ break;
+ }
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize: {
+ uint64_t blockSize = parcBuffer_GetUint64(value);
+ ccnxManifestHashGroup_SetBlockSize(group, blockSize);
+ break;
+ }
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize: {
+ uint64_t entrySize = parcBuffer_GetUint64(value);
+ ccnxManifestHashGroup_SetEntrySize(group, entrySize);
+ break;
+ }
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight: {
+ uint64_t treeHeight = parcBuffer_GetUint64(value);
+ ccnxManifestHashGroup_SetTreeHeight(group, treeHeight);
+ break;
+ }
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256: {
+ ccnxManifestHashGroup_SetOverallDataDigest(group, value);
+ break;
+ }
+ }
+
+ parcBuffer_Release(&value);
+ }
+
+ return success;
+}
+
+static bool
+_decodeHashGroup(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, CCNxManifestHashGroup *group, size_t length)
+{
+ bool success = true;
+ size_t offset = 0;
+
+ while (offset < length) {
+ uint16_t type = ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t value_length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ offset += (4 + value_length);
+
+ switch (type) {
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata: {
+ success = _decodeHashGroupMetadata(decoder, group, value_length);
+ if (!success) {
+ return false;
+ }
+ break;
+ }
+
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer: {
+ PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, value_length);
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer);
+ parcBuffer_Release(&buffer);
+ break;
+ }
+
+ case CCNxCodecSchemaV1Types_CCNxManifestHashGroup_ManifestPointer: {
+ PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, value_length);
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Manifest, buffer);
+ parcBuffer_Release(&buffer);
+ break;
+ }
+
+ default:
+ // if we do not know the TLV type, put it in this container's unknown list
+ success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, value_length, CCNxCodecSchemaV1TlvDictionary_Lists_MESSAGE_LIST);
+ break;
+ }
+
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+ }
+
+ CCNxManifestInterface *manifest = ccnxManifestInterface_GetInterface(packetDictionary);
+ manifest->addHashGroup(packetDictionary, group);
+
+ return success;
+}
+
+static bool
+_decodeType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+{
+ bool success = false;
+ switch (type) {
+ case CCNxCodecSchemaV1Types_CCNxMessage_Name: {
+ success = ccnxCodecTlvUtilities_PutAsName(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+ break;
+ }
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_HashGroup: {
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ success = _decodeHashGroup(decoder, packetDictionary, group, length);
+ ccnxManifestHashGroup_Release(&group);
+ break;
+ }
+
+ default:
+ // if we do not know the TLV type, put it in this container's unknown list
+ success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_Lists_MESSAGE_LIST);
+ break;
+ }
+
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+ return success;
+}
+
+/*
+ * We are given a decoder that points to the first TLV of a list of TLVs. We keep walking the
+ * list until we come to the end of the decoder.
+ */
+bool
+ccnxCodecSchemaV1ManifestDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *manifestDictionary)
+{
+ return ccnxCodecTlvUtilities_DecodeContainer(decoder, manifestDictionary, _decodeType);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h
new file mode 100755
index 00000000..1726e41e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * @file ccnxCodecSchemaV1_ManifestDecoder.h
+ * @brief Decode the body of a CCNx Manifest.
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_ManifestDecoder_h
+#define TransportRTA_ccnxCodecSchemaV1_ManifestDecoder_h
+
+#include <stdbool.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+/**
+ * Decode a V1 Manifest.
+ *
+ * The decoder should point to byte 0 of a Manifest (message) TLV.
+ * The results are put in the provided dictionary.
+ * It is an error if the message does not extend to the end of
+ * the decoder.
+ *
+ * @param [in] decoder The decoder to parse
+ * @param [in] manifestDictionary The results go directly in to the provided dictionary.
+ *
+ * @return true Fully parsed interest, no errors
+ * @return false Error decoding, decoder is left pointing to the first byte of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1ManifestDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *manifestDictionary);
+
+#endif // TransportRTA_ccnxCodecSchemaV1_ManifestDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c
new file mode 100644
index 00000000..0d8f52bf
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+#include <ccnx/common/ccnx_Manifest.h>
+#include <ccnx/common/ccnx_ManifestHashGroup.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <ccnx/common/ccnx_PayloadType.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+
+static size_t
+_appendPointer(CCNxCodecTlvEncoder *encoder, CCNxManifestHashGroupPointer *ptr)
+{
+ const PARCBuffer *digest = ccnxManifestHashGroupPointer_GetDigest(ptr);
+ CCNxManifestHashGroupPointerType type = ccnxManifestHashGroupPointer_GetType(ptr);
+
+ ssize_t length = -1;
+ switch (type) {
+ case CCNxManifestHashGroupPointerType_Data:
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer, (PARCBuffer *) digest);
+ break;
+ case CCNxManifestHashGroupPointerType_Manifest:
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_ManifestPointer, (PARCBuffer *) digest);
+ break;
+ default:
+ assertTrue(false, "Invalid pointer type %d", type);
+ }
+
+ if (length < 0) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder));
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+ }
+
+ return length;
+}
+
+ssize_t
+_appendMetadata(CCNxCodecTlvEncoder *encoder, CCNxManifestHashGroup *group)
+{
+ ssize_t length = 0;
+
+ // Pre-populate this field -- we'll come back and fill in the length after we're done
+ size_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata, length);
+
+ // Now append all metadata that exists in the hash group.
+ const CCNxName *locator = ccnxManifestHashGroup_GetLocator(group);
+ if (locator != NULL) {
+ char *nameString = ccnxName_ToString(locator);
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(nameString);
+ length += ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator, nameBuffer);
+ parcBuffer_Release(&nameBuffer);
+ parcMemory_Deallocate(&nameString);
+ }
+
+ size_t dataSize = ccnxManifestHashGroup_GetDataSize(group);
+ if (dataSize > 0) {
+ length += ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize, dataSize);
+ }
+
+ size_t blockSize = ccnxManifestHashGroup_GetBlockSize(group);
+ if (blockSize > 0) {
+ length += ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize, blockSize);
+ }
+
+ size_t entrySize = ccnxManifestHashGroup_GetEntrySize(group);
+ if (entrySize > 0) {
+ length += ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize, entrySize);
+ }
+
+ size_t treeSize = ccnxManifestHashGroup_GetTreeHeight(group);
+ if (treeSize > 0) {
+ length += ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight, treeSize);
+ }
+
+ const PARCBuffer *dataDigest = ccnxManifestHashGroup_GetOverallDataDigest(group);
+ if (dataDigest != NULL) {
+ length += ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256, (PARCBuffer *) dataDigest);
+ }
+
+ // Rewind back to the container opening and fill in the length
+ size_t endPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ccnxCodecTlvEncoder_PutUint16(encoder, startPosition, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata);
+ ccnxCodecTlvEncoder_PutUint16(encoder, startPosition + 2, length);
+ ccnxCodecTlvEncoder_SetPosition(encoder, endPosition);
+
+ return endPosition - startPosition;
+}
+
+ssize_t
+ccnxCodecSchemaV1ManifestEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+
+ ssize_t numHashGroups = ccnxTlvDictionary_ListSize(packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HASH_GROUP_LIST);
+ for (size_t i = 0; i < numHashGroups; i++) {
+ // Skip past the TL of the hash group to append the pointers inside
+ ssize_t groupLength = 0;
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_HashGroup, groupLength);
+
+ CCNxManifestInterface *interface = ccnxManifestInterface_GetInterface(packetDictionary);
+ CCNxManifestHashGroup *group = interface->getHashGroup(packetDictionary, i);
+
+ // Encode any metadata, if present.
+ if (ccnxManifestHashGroup_HasMetadata(group)) {
+ groupLength += _appendMetadata(encoder, group);
+ }
+
+ // Append the HashGroup pointers
+ size_t numPointers = ccnxManifestHashGroup_GetNumberOfPointers(group);
+ for (size_t p = 0; p < numPointers; p++) {
+ CCNxManifestHashGroupPointer *ptr = ccnxManifestHashGroup_GetPointerAtIndex(group, p);
+ ssize_t ptrLength = _appendPointer(encoder, ptr);
+ if (ptrLength < 0) {
+ return ptrLength;
+ }
+ groupLength += ptrLength;
+ }
+
+ // Now that we know the overall length, rewind back to the start and append the TL
+ // part of the container.
+ size_t endPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ssize_t offset = endPosition - groupLength - 4;
+ ccnxCodecTlvEncoder_PutUint16(encoder, offset, CCNxCodecSchemaV1Types_CCNxMessage_HashGroup);
+ ccnxCodecTlvEncoder_PutUint16(encoder, offset + 2, groupLength);
+ ccnxCodecTlvEncoder_SetPosition(encoder, endPosition);
+
+ length += groupLength + 4;
+
+ ccnxManifestHashGroup_Release(&group);
+ }
+
+ return length;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h
new file mode 100755
index 00000000..4951cf80
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * @file ccnxCodecSchemaV1_ManifestEncoder.h
+ * @brief Encode a V1 Manifest.
+ *
+ */
+
+#ifndef ccnx_common_ccnxCodecSchemaV1_ManifestEncoder_h
+#define ccnx_common_ccnxCodecSchemaV1_ManifestEncoder_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+
+ssize_t ccnxCodecSchemaV1ManifestEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary);
+
+#endif // ccnx_common_ccnxCodecSchemaV1_ManifestEncoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.c
new file mode 100644
index 00000000..f0dea7a6
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <ccnx/common/ccnx_PayloadType.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+
+static bool
+_translateWirePayloadTypeToCCNxPayloadType(CCNxCodecSchemaV1Types_PayloadType wireFormatType, CCNxPayloadType *payloadTypePtr)
+{
+ bool success = true;
+ switch (wireFormatType) {
+ case CCNxCodecSchemaV1Types_PayloadType_Data:
+ *payloadTypePtr = CCNxPayloadType_DATA;
+ break;
+
+ case CCNxCodecSchemaV1Types_PayloadType_Key:
+ *payloadTypePtr = CCNxPayloadType_KEY;
+ break;
+
+ case CCNxCodecSchemaV1Types_PayloadType_Link:
+ *payloadTypePtr = CCNxPayloadType_LINK;
+ break;
+
+ default:
+ // unknown type
+ success = false;
+ }
+ return success;
+}
+
+/**
+ * Translates the wire format value for the PayloadType to CCNxPayloadType
+ */
+static bool
+_decodePayloadType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t length)
+{
+ CCNxPayloadType payloadType;
+
+ uint64_t wireFormatVarInt;
+ bool success = ccnxCodecTlvDecoder_GetVarInt(decoder, length, &wireFormatVarInt);
+ if (success) {
+ CCNxCodecSchemaV1Types_PayloadType wireFormatType = (CCNxCodecSchemaV1Types_PayloadType) wireFormatVarInt;
+
+ success = _translateWirePayloadTypeToCCNxPayloadType(wireFormatType, &payloadType);
+ }
+
+ if (success) {
+ success = ccnxTlvDictionary_PutInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE, payloadType);
+ }
+
+ return success;
+}
+
+static bool
+_decodeType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+{
+ bool success = false;
+ switch (type) {
+ case CCNxCodecSchemaV1Types_CCNxMessage_Name:
+ success = ccnxCodecTlvUtilities_PutAsName(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+ break;
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_Payload:
+ success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+ break;
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_KeyIdRestriction:
+ success = ccnxCodecTlvUtilities_PutAsHash(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION);
+ break;
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_ContentObjectHashRestriction:
+ success = ccnxCodecTlvUtilities_PutAsHash(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION);
+ break;
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_PayloadType:
+ success = _decodePayloadType(decoder, packetDictionary, length);
+ break;
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_ExpiryTime:
+ success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME);
+ break;
+
+ case CCNxCodecSchemaV1Types_CCNxMessage_EndChunkNumber:
+ success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT);
+ break;
+
+ default:
+ // if we do not know the TLV type, put it in this container's unknown list
+ success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_Lists_MESSAGE_LIST);
+ break;
+ }
+
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+
+ return success;
+}
+
+/*
+ * We are given a decoder that points to the first TLV of a list of TLVs. We keep walking the
+ * list until we come to the end of the decoder.
+ */
+bool
+ccnxCodecSchemaV1MessageDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ return ccnxCodecTlvUtilities_DecodeContainer(decoder, packetDictionary, _decodeType);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h
new file mode 100755
index 00000000..30a998aa
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_MessageDecoder.h
+ * @brief <#Brief Description#>
+ *
+ * Decodes the CCNx message body for an Interest or a ContentObject.
+ *
+ * The current CPI Control packet does not use the MessageDecoder or MessageEncoder. It is handled
+ * entirely in the Packet{De,En}coder.
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_MessageDecoder_h
+#define TransportRTA_ccnxCodecSchemaV1_MessageDecoder_h
+
+#include <stdbool.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+/**
+ * The decode a V1 message, maybe any message type
+ *
+ * The decoder should point to byte 0 of the message TLV
+ * The results are put in the provided dictionary.
+ * It is an error if the message does not extend to the end of
+ * the decoder.
+ *
+ * @param [in] decoder The decoder to parse
+ * @param [in] contentObjectDictionary The results go directly in to the provided dictionary.
+ *
+ * @return true Fully parsed interest, no errors
+ * @return false Error decoding, decoder is left pointing to the first byte of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1MessageDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *contentObjectDictionary);
+
+
+#endif // TransportRTA_ccnxCodecSchemaV1_MessageDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.c
new file mode 100755
index 00000000..7aa14627
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/ccnx_PayloadType.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+#include <ccnx/common/ccnx_Manifest.h>
+#include <ccnx/common/ccnx_ManifestHashGroup.h>
+
+static ssize_t
+_encodeName(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = -1;
+ CCNxName *name = ccnxTlvDictionary_GetName(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+ if (name != NULL) {
+ length = ccnxCodecSchemaV1NameCodec_Encode(encoder, CCNxCodecSchemaV1Types_CCNxMessage_Name, name);
+ }
+
+ // required field for everything except CCNxContentObjects
+ if (!ccnxTlvDictionary_IsContentObject(packetDictionary) && length < 0) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder));
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+ } else if (ccnxTlvDictionary_IsContentObject(packetDictionary) && name == NULL) {
+ length = 0;
+ }
+
+ return length;
+}
+
+static ssize_t
+_encodeJsonPayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCJSON *json = ccnxTlvDictionary_GetJson(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+ if (json != NULL) {
+ char *jsonString = parcJSON_ToCompactString(json);
+ size_t len = strlen(jsonString);
+ length = ccnxCodecTlvEncoder_AppendArray(encoder, CCNxCodecSchemaV1Types_CCNxMessage_Payload, len, (uint8_t *) jsonString);
+ }
+ return length;
+}
+
+static ssize_t
+_encodePayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+ if (buffer != NULL) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_Payload, buffer);
+ }
+ return length;
+}
+
+static ssize_t
+_encodePayloadType(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE)) {
+ CCNxPayloadType payloadType = (CCNxPayloadType) ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE);
+
+ CCNxCodecSchemaV1Types_PayloadType wireFormatType = CCNxCodecSchemaV1Types_PayloadType_Data;
+
+ switch (payloadType) {
+ case CCNxPayloadType_KEY:
+ wireFormatType = CCNxCodecSchemaV1Types_PayloadType_Key;
+ break;
+
+ case CCNxPayloadType_LINK:
+ wireFormatType = CCNxCodecSchemaV1Types_PayloadType_Link;
+ break;
+
+ default:
+ // anything else is encoded as DATA
+ break;
+ }
+
+ length = ccnxCodecTlvEncoder_AppendUint8(encoder, CCNxCodecSchemaV1Types_CCNxMessage_PayloadType, wireFormatType);
+ } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE)) {
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE);
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_PayloadType, buffer);
+ }
+
+ return length;
+}
+
+static ssize_t
+_encodeExpiryTime(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME)) {
+ uint64_t millis = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME);
+ length = ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxMessage_ExpiryTime, millis);
+ } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME)) {
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME);
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_ExpiryTime, buffer);
+ }
+
+ return length;
+}
+
+static ssize_t
+_encodeEndChunkNumber(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT)) {
+ uint64_t endChunkId = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT);
+ length = ccnxCodecTlvEncoder_AppendVarInt(encoder, CCNxCodecSchemaV1Types_CCNxMessage_EndChunkNumber, endChunkId);
+ } else {
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT);
+ if (buffer != NULL) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_EndChunkNumber, buffer);
+ }
+ }
+ return length;
+}
+
+static ssize_t
+_encodeKeyIdRestriction(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCCryptoHash *hash = ccnxTlvDictionary_GetObject(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION);
+ if (hash != NULL) {
+ size_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_KeyIdRestriction, 0);
+ length = ccnxCodecSchemaV1HashCodec_Encode(encoder, hash);
+ if (length < 0) {
+ return length;
+ }
+
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, length);
+ length += 4; // this accounts for the TL fields
+ }
+ return length;
+}
+
+static ssize_t
+_encodeContentObjectHashRestriction(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCCryptoHash *hash = ccnxTlvDictionary_GetObject(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION);
+ if (hash != NULL) {
+ size_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_ContentObjectHashRestriction, 0);
+ length = ccnxCodecSchemaV1HashCodec_Encode(encoder, hash);
+ if (length < 0) {
+ return length;
+ }
+
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, length);
+ length += 4; // this accounts for the TL fields
+ }
+ return length;
+}
+
+
+static ssize_t
+_encodeContentObject(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t result;
+
+ result = _encodeName(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodePayloadType(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeExpiryTime(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeEndChunkNumber(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodePayload(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ return length;
+}
+
+static ssize_t
+_encodeInterest(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t result;
+
+ result = _encodeName(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeKeyIdRestriction(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeContentObjectHashRestriction(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodePayload(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ return length;
+}
+
+static ssize_t
+_encodeControl(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t result;
+
+ result = _encodeName(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeJsonPayload(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ return length;
+}
+
+static ssize_t
+_encodeManifest(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t result;
+
+ result = _encodeName(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ return length;
+}
+
+ssize_t
+ccnxCodecSchemaV1MessageEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ assertNotNull(packetDictionary, "Parameter packetDictionary must be non-null");
+
+ ssize_t length = -1;
+
+ if (ccnxTlvDictionary_IsInterest(packetDictionary)) {
+ length = _encodeInterest(encoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsInterestReturn(packetDictionary)) {
+ length = _encodeInterest(encoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsContentObject(packetDictionary)) {
+ length = _encodeContentObject(encoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsControl(packetDictionary)) {
+ length = _encodeControl(encoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsManifest(packetDictionary)) {
+ length = _encodeManifest(encoder, packetDictionary);
+ } else {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETTYPE, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder));
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+ length = -1;
+ }
+
+
+ if (length >= 0) {
+ // Put custom fields all last
+ ssize_t customLength = ccnxCodecTlvUtilities_EncodeCustomList(encoder, packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_MESSAGE_LIST);
+ if (customLength < 0) {
+ return customLength;
+ }
+ length += customLength;
+ }
+
+ return length;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h
new file mode 100755
index 00000000..d49417fb
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_MessageEncoder.h
+ * @brief Encode the list of optional headers
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_MessageEncoder_h
+#define TransportRTA_ccnxCodecSchemaV1_MessageEncoder_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <parc/security/parc_Signer.h>
+
+/**
+ * Encodes the body of the CCNxMessage
+ *
+ * Encodes an Interest, ContentObject, or Control message
+ *
+ * @param [in] encoder Appends the CCNx message to the encoder
+ * @param [in] packetDictionary The fields to encode
+ *
+ * @return non-negative Total bytes appended to encoder
+ * @return -1 An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1MessageEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary);
+
+#endif // TransportRTA_ccnxCodecSchemaV1_MessageEncoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c
new file mode 100755
index 00000000..a769477f
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h>
+
+size_t
+ccnxCodecSchemaV1NameCodec_Encode(CCNxCodecTlvEncoder *encoder, uint16_t type, const CCNxName *name)
+{
+ assertNotNull(encoder, "Parameter encoder must be non-null");
+ assertNotNull(name, "Parameter name must be non-null");
+
+ size_t containerPosition = ccnxCodecTlvEncoder_Position(encoder);
+ size_t containerLength = ccnxCodecTlvEncoder_AppendContainer(encoder, type, 0);
+
+ size_t segmentCount = ccnxName_GetSegmentCount(name);
+ size_t innerLength = 0;
+ for (int i = 0; i < segmentCount; i++) {
+ CCNxNameSegment *segment = ccnxName_GetSegment(name, i);
+ innerLength += ccnxCodecSchemaV1NameSegmentCodec_Encode(encoder, segment);
+ }
+
+ // now go back and fixup the container's length
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, containerPosition, innerLength);
+
+ return containerLength + innerLength;
+}
+
+CCNxName *
+ccnxCodecSchemaV1NameCodec_Decode(CCNxCodecTlvDecoder *decoder, uint16_t type)
+{
+ CCNxName *name = NULL;
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) {
+ uint16_t tlvtype = ccnxCodecTlvDecoder_PeekType(decoder);
+ if (tlvtype == type) {
+ // call just for the side-effect of advancing the buffer
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ name = ccnxCodecSchemaV1NameCodec_DecodeValue(decoder, length);
+ }
+ }
+
+ return name;
+}
+
+CCNxName *
+ccnxCodecSchemaV1NameCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, uint16_t length)
+{
+ CCNxName *name = NULL;
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) {
+ name = ccnxName_Create();
+ size_t nameEnd = ccnxCodecTlvDecoder_Position(decoder) + length;
+
+ while (ccnxCodecTlvDecoder_Position(decoder) < nameEnd) {
+ CCNxNameSegment *segment = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder);
+ ccnxName_Append(name, segment);
+ ccnxNameSegment_Release(&segment);
+ }
+ }
+ return name;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h
new file mode 100755
index 00000000..6c3298a2
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_NameCodec.h
+ * @brief TLV codec for CCNx types
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef CCNxCodecSchemaV1_NameCodec_h
+#define CCNxCodecSchemaV1_NameCodec_h
+
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+#include <ccnx/common/ccnx_Name.h>
+
+/**
+ * Encodes the name to the TLV Encoder
+ *
+ * Will append the Name after the current encoder location
+ *
+ * @param [in] type The TLV type to use for the Name container
+ *
+ * @return bytes The number of bytes appended to the encoder
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecSchemaV1NameCodec_Encode(CCNxCodecTlvEncoder *encoder, uint16_t type, const CCNxName *name);
+
+/**
+ * Decode the buffer as a CCNxName beginning at the current position
+ *
+ * The buffer must be pointing to the beginnig of the "type". The decoder will
+ * verify that the type matches `type'. If it does not match, it will return NULL.
+ *
+ * @param [in] decoder The decoder
+ * @param [in] type The TLV type that the decoder should currently be pointing at
+ *
+ * @return non-null The CCNxName decoded
+ * @return null An error: either type did not match or some other error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxName *ccnxCodecSchemaV1NameCodec_Decode(CCNxCodecTlvDecoder *decoder, uint16_t type);
+
+/**
+ * The decoder points to the first byte of the Name "value"
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] decoder The Tlv Decoder pointing to the start of the Name value
+ * @param [in] length the length of the Name value
+ *
+ * @return non-null A parsed name
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxName *ccnxCodecSchemaV1NameCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, uint16_t length);
+#endif // CCNxCodecSchemaV1_NameCodec_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c
new file mode 100755
index 00000000..55d02bab
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h>
+
+size_t
+ccnxCodecSchemaV1NameSegmentCodec_Encode(CCNxCodecTlvEncoder *encoder, CCNxNameSegment *segment)
+{
+ assertTrue(ccnxNameSegment_Length(segment) <= UINT16_MAX,
+ "Name segment too long! length %zu maximum %u",
+ ccnxNameSegment_Length(segment),
+ UINT16_MAX);
+
+ uint16_t segment_type = ccnxNameSegment_GetType(segment);
+ PARCBuffer *value = ccnxNameSegment_GetValue(segment);
+
+ return ccnxCodecTlvEncoder_AppendBuffer(encoder, segment_type, value);
+}
+
+CCNxNameSegment *
+ccnxCodecSchemaV1NameSegmentCodec_Decode(CCNxCodecTlvDecoder *decoder)
+{
+ CCNxNameSegment *segment = NULL;
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) {
+ uint16_t type = ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) {
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(decoder, length);
+ segment = ccnxNameSegment_CreateTypeValue(type, value);
+ parcBuffer_Release(&value);
+ }
+ }
+
+ return segment;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h
new file mode 100755
index 00000000..c6797cff
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_NameSegmentCodec.h
+ * @brief TLV codec for CCNx types
+ *
+ * Encode/decode a CCNx name segment using the V1 schema
+ *
+ */
+
+#ifndef CCNxCodecSchemaV1_NameSegmentCodec_h
+#define CCNxCodecSchemaV1_NameSegmentCodec_h
+
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+#include <ccnx/common/ccnx_Name.h>
+
+/**
+ * Encodes the name segment using the segment type as the TLV type
+ *
+ * Appends the name segment to the encoder. The TLV type is implicit in
+ * the CCNxNameSegment.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return number The number of bytes appended, including the type and length.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t ccnxCodecSchemaV1NameSegmentCodec_Encode(CCNxCodecTlvEncoder *encoder, CCNxNameSegment *segment);
+
+/**
+ * Decodes the current location of the decoder as a CCNxNameSegment
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] decoder The decoder object
+ *
+ * @return non-null A CCNxNameSement
+ * @return null An error, such as buffer underrun
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxNameSegment *ccnxCodecSchemaV1NameSegmentCodec_Decode(CCNxCodecTlvDecoder *decoder);
+#endif // CCNxCodecSchemaV1_NameSegmentCodec_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.c
new file mode 100755
index 00000000..48554b9a
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+static bool
+_decodeType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+{
+ bool success = false;
+ switch (type) {
+ case CCNxCodecSchemaV1Types_OptionalHeaders_InterestFragment:
+ success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG);
+ break;
+
+ case CCNxCodecSchemaV1Types_OptionalHeaders_ContentObjectFragment:
+ success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG);
+ break;
+
+ case CCNxCodecSchemaV1Types_OptionalHeaders_InterestLifetime:
+ // its a time, so use an Integer
+ success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+ break;
+
+ case CCNxCodecSchemaV1Types_OptionalHeaders_RecommendedCacheTime:
+ // its a time, so use an Integer
+ success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime);
+ break;
+ case CCNxCodecSchemaV1Types_OptionalHeaders_PathLabel:
+ success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel);
+ break;
+
+ default: {
+ // if we do not know the TLV type, put it in this container's unknown list
+ success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS);
+ }
+ break;
+ }
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+ return success;
+}
+
+/*
+ * We are given a decoder that points to the first TLV of a list of TLVs. We keep walking the
+ * list until we come to the end of the decoder.
+ */
+bool
+ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ return ccnxCodecTlvUtilities_DecodeContainer(decoder, packetDictionary, _decodeType);
+}
+
+// ==== Getters
+
+PARCBuffer *
+ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG);
+ return buffer;
+}
+
+PARCBuffer *
+ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(CCNxTlvDictionary *packetDictionary)
+{
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG);
+ return buffer;
+}
+
+uint64_t
+ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader(CCNxTlvDictionary *packetDictionary)
+{
+ uint64_t lifetime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+ return lifetime;
+}
+
+uint64_t
+ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader(CCNxTlvDictionary *packetDictionary)
+{
+ uint64_t cachetime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime);
+ return cachetime;
+}
+
+uint64_t
+ccnxCodecSchemaV1OptionalHeadersDecoder_GetPathLabel(CCNxTlvDictionary *packetDictionary)
+{
+ uint64_t pathLabel = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel);
+ return pathLabel;
+}
+
+PARCBuffer *
+ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(CCNxTlvDictionary *packetDictionary, uint32_t key)
+{
+ PARCBuffer *buffer = ccnxTlvDictionary_ListGetByType(packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS, key);
+ return buffer;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h
new file mode 100755
index 00000000..94463ad1
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_OptionalHeadersDecoder.h
+ * @brief Decode the list of optional headers
+ *
+ * A reference to each optional header will be stored in the provided CCNxTlvDictionary.
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_OptionalHeadersDecoder_h
+#define TransportRTA_ccnxCodecSchemaV1_OptionalHeadersDecoder_h
+
+#include <stdbool.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+/**
+ * The decode a list of Version 1 optional headers
+ *
+ * The decoder should point to the first byte of the first optional header.
+ * The decoder will advance until the end of the buffer.
+ * It is an error for the last optional header to either go beyond the end of the
+ * decoder or for it to underrun the end of the decoder. It must exactly align.
+ *
+ * @param [in] decoder The decoder to parse
+ * @param [in] packetDictionary The results go directly in to the provided dictionary.
+ *
+ * @return true Fully parsed interest, no errors
+ * @return false Error decoding, decoder is left pointing to the first byte of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the Interest Fragment header buffer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] packetDictionary The packet dictionary
+ *
+ * @return non-null The header buffer
+ * @return null The header does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the Content Object Fragment header buffer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] packetDictionary The packet dictionary
+ *
+ * @return non-null The header buffer
+ * @return null The header does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the Interest Lifetime header value
+ *
+ * Returns the byte array of the Interest Lifetime, which is encoded as a uint64_t milli-seconds
+ * since the UTC epoch. The PARCBuffer returned wraps the underlying memory so any changes to the
+ * buffer will be reflected in the header.
+ *
+ * @param [in] packetDictionary The packet dictionary
+ *
+ * @return number The Interest Lifetime
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint64_t ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * A convenience function to return the Recommended Cache Time (RCT) header
+ *
+ * Returns the byte array of the RCT, which is encoded as a uint64_t milli-seconds
+ * since the UTC epoch. The PARCBuffer returned wraps the underlying memory so any changes to the
+ * buffer will be reflected in the header.
+ *
+ * @param [in] packetDictionary The packet dictionary
+ *
+ * @return number The Recommended Cache Time
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint64_t ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader(CCNxTlvDictionary *packetDictionary);
+
+uint64_t ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedPathLabel(CCNxTlvDictionary *packetDictionary);
+
+/**
+ * Retrieves a TLV header that is not part of the V1 schema spec
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-NULL The header
+ * @return NULL The header field does not exist
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(CCNxTlvDictionary *packetDictionary, uint32_t key);
+
+#endif // TransportRTA_ccnxCodecSchemaV1_OptionalHeadersDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.c
new file mode 100755
index 00000000..f108a1c3
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+
+static ssize_t
+_EncodeInterestLifetime(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+
+ // allow either encoding as an Integer or as a Buffer
+
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime)) {
+ uint64_t lifetime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+ length = ccnxCodecTlvEncoder_AppendVarInt(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_InterestLifetime, lifetime);
+ } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime)) {
+ PARCBuffer *lifetime = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+ length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_InterestLifetime, lifetime);
+ }
+
+ return length;
+}
+
+static ssize_t
+_EncodeRecommendedCacheTime(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+
+ // allow either encoding as an Integer or as a Buffer
+
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime)) {
+ uint64_t cacheTime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime);
+ length = ccnxCodecTlvEncoder_AppendVarInt(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_RecommendedCacheTime, cacheTime);
+ } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime)) {
+ PARCBuffer *cacheTime = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime);
+ length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_RecommendedCacheTime, cacheTime);
+ }
+
+ return length;
+}
+
+static ssize_t
+_EncodePathLabel(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel)) {
+ uint16_t pathLabel = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel);
+ length = ccnxCodecTlvEncoder_AppendVarInt(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_PathLabel, pathLabel);
+ } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel)) {
+ PARCBuffer *pathLabel = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel);
+ length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_PathLabel, pathLabel);
+ }
+
+ return length;
+}
+
+static ssize_t
+_EncodeInterestFrag(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG);
+ if (buffer != NULL) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_InterestFragment, buffer);
+ }
+ return length;
+}
+
+static ssize_t
+_EncodeContentObjectFrag(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG);
+ if (buffer != NULL) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_ContentObjectFragment, buffer);
+ }
+ return length;
+}
+
+static ssize_t
+_EncodeInterestHeaders(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t intFragLength = _EncodeInterestFrag(optionalHeadersEncoder, packetDictionary);
+ if (intFragLength < 0) {
+ return intFragLength;
+ }
+ length += intFragLength;
+
+ ssize_t intLifeLength = _EncodeInterestLifetime(optionalHeadersEncoder, packetDictionary);
+ if (intLifeLength < 0) {
+ return intLifeLength;
+ }
+ length += intLifeLength;
+
+ ssize_t customLength = ccnxCodecTlvUtilities_EncodeCustomList(optionalHeadersEncoder, packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS);
+ if (customLength < 0) {
+ return customLength;
+ }
+ length += customLength;
+
+ return length;
+}
+
+static ssize_t
+_EncodeContentObjectHeaders(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t result;
+
+ result = _EncodeContentObjectFrag(optionalHeadersEncoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _EncodeRecommendedCacheTime(optionalHeadersEncoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _EncodePathLabel(optionalHeadersEncoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = ccnxCodecTlvUtilities_EncodeCustomList(optionalHeadersEncoder, packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ return length;
+}
+
+
+ssize_t
+ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ assertNotNull(optionalHeadersEncoder, "Parameter optionalHeadersEncoder must be non-null");
+ assertNotNull(packetDictionary, "Parameter packetDictionary must be non-null");
+
+ ssize_t result = 0;
+ if (ccnxTlvDictionary_IsInterest(packetDictionary) || ccnxTlvDictionary_IsInterestReturn(packetDictionary)) {
+ result = _EncodeInterestHeaders(optionalHeadersEncoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsContentObject(packetDictionary) || ccnxTlvDictionary_IsManifest(packetDictionary)) {
+ result = _EncodeContentObjectHeaders(optionalHeadersEncoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsControl(packetDictionary)) {
+ result = ccnxCodecTlvUtilities_EncodeCustomList(optionalHeadersEncoder, packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS);
+ } else {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETTYPE, __func__, __LINE__, ccnxCodecTlvEncoder_Position(optionalHeadersEncoder));
+ ccnxCodecTlvEncoder_SetError(optionalHeadersEncoder, error);
+ ccnxCodecError_Release(&error);
+ result = -1;
+ }
+
+ return result;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h
new file mode 100755
index 00000000..3f7632ca
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_OptionalHeadersEncoder.h
+ * @brief Encode the list of optional headers
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_OptionalHeadersEncoder_h
+#define TransportRTA_ccnxCodecSchemaV1_OptionalHeadersEncoder_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+
+/**
+ * Appends the Optional Headers to the encoderder
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] encoder An allocated encoder to append to
+ * @param [in] packetDictionary The dictionary containing the optional headers
+ *
+ * @return non-negative Total bytes appended to encoder
+ * @return -1 An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary);
+
+#endif // TransportRTA_ccnxCodecSchemaV1_OptionalHeadersEncoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c
new file mode 100644
index 00000000..692b3291
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/internal/ccnx_WireFormatFacadeV1.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h>
+
+typedef struct rta_tlv_schema_v1_data {
+ CCNxCodecTlvDecoder *decoder;
+ CCNxTlvDictionary *packetDictionary;
+} _CCNxCodecSchemaV1Data;
+
+/**
+ * Decodes the per-hop optional headers
+ *
+ * @param [in] data The packet decoder state
+ *
+ * @return true successful decode
+ * @return false A decoding error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+_decodeOptionalHeaders(_CCNxCodecSchemaV1Data *data)
+{
+ size_t optionalHeaderLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetOptionalHeaderLength(data->packetDictionary);
+ CCNxCodecTlvDecoder *optionalHeaderDecoder = ccnxCodecTlvDecoder_GetContainer(data->decoder, optionalHeaderLength);
+
+ bool success = ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(optionalHeaderDecoder, data->packetDictionary);
+
+ ccnxCodecTlvDecoder_Destroy(&optionalHeaderDecoder);
+ return success;
+}
+
+/**
+ * Decodes the "value" of the CPI "TLV"
+ *
+ * the CPI packet is encoded as a single TLV container of type 0xBEEF (detected in _decodeMessage).
+ * At this point, the cpiDecoder wraps the CPI payload, which is the encapsulated JSON
+ *
+ * @param [in] cpiDecoder Decoder wrapping the value
+ * @param [in] packetDictionary where to place the results
+ *
+ * @retval true Good decode
+ * @retval false An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+_decodeCPI(CCNxCodecTlvDecoder *cpiDecoder, CCNxTlvDictionary *packetDictionary)
+{
+ // we just take the whole contents of the decoder and put in the the PAYLOAD dictionary entry.
+ size_t length = ccnxCodecTlvDecoder_Remaining(cpiDecoder);
+ PARCBuffer *payload = ccnxCodecTlvDecoder_GetValue(cpiDecoder, length);
+
+ PARCJSON *json = parcJSON_ParseBuffer(payload);
+
+ bool success = ccnxTlvDictionary_PutJson(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, json);
+ parcJSON_Release(&json);
+ parcBuffer_Release(&payload);
+ return success;
+}
+
+/**
+ * Decodes the CCNx message inside a TLV packet
+ *
+ * Creates an inner decoder that slices the decode buffer then passes that and our
+ * message dictionary to the appropriate inner decoder.
+ *
+ * @param [in] data The packet decoder state
+ *
+ * @return true successful decode
+ * @return false A decoding error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+_decodeMessage(_CCNxCodecSchemaV1Data *data)
+{
+ bool success = false;
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, 4)) {
+ // what kind of message are we looking at?
+ // Note that this is based on the TLV container, not the fixed head PacketType
+ uint16_t tlv_type = ccnxCodecTlvDecoder_GetType(data->decoder);
+ uint16_t tlv_length = ccnxCodecTlvDecoder_GetLength(data->decoder);
+
+ // ensure its a proper tlv type
+ switch (tlv_type) {
+ case CCNxCodecSchemaV1Types_MessageType_Interest: // fallthrough
+ case CCNxCodecSchemaV1Types_MessageType_ContentObject: // fallthrough
+ case CCNxCodecSchemaV1Types_MessageType_Control: // fallthrough
+ case CCNxCodecSchemaV1Types_MessageType_Manifest: // fallthrough
+ break;
+
+ default:
+ return false;
+ }
+
+ // cross check with the fixed header value
+ // ccnxCodecSchemaV1FixedHeaderDecoder_Decode ensures that PacketLength is not less than HeaderLength
+ size_t messageLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(data->packetDictionary) - ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(data->packetDictionary);
+
+ if (tlv_length <= messageLength && ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, tlv_length)) {
+ // This decode is for the "value" of the message, it does not include the wrapper
+ CCNxCodecTlvDecoder *messageDecoder = ccnxCodecTlvDecoder_GetContainer(data->decoder, tlv_length);
+
+ if (tlv_type == CCNxCodecSchemaV1Types_MessageType_Control) {
+ // the CPI messages are not a proper "message" in that there's no inner TLV, its just data
+ success = _decodeCPI(messageDecoder, data->packetDictionary);
+ } else if (tlv_type == CCNxCodecSchemaV1Types_MessageType_Manifest) {
+ ccnxTlvDictionary_SetMessageType_Manifest(data->packetDictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ success = ccnxCodecSchemaV1ManifestDecoder_Decode(messageDecoder, data->packetDictionary);
+ } else {
+ success = ccnxCodecSchemaV1MessageDecoder_Decode(messageDecoder, data->packetDictionary);
+ }
+
+ ccnxCodecTlvDecoder_Destroy(&messageDecoder);
+ } else {
+ // raise an error
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_TOO_LONG, __func__, __LINE__, ccnxCodecTlvDecoder_Position(data->decoder));
+ ccnxCodecTlvDecoder_SetError(data->decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+ }
+
+ return success;
+}
+
+static bool
+_decodeValidationAlg(_CCNxCodecSchemaV1Data *data)
+{
+ bool success = false;
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, 4)) {
+ // what kind of message are we looking at?
+ // Note that this is based on the TLV container, not the fixed head PacketType
+ uint16_t tlv_type = ccnxCodecTlvDecoder_GetType(data->decoder);
+ uint16_t tlv_length = ccnxCodecTlvDecoder_GetLength(data->decoder);
+
+ if (tlv_type == CCNxCodecSchemaV1Types_MessageType_ValidationAlg &&
+ ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, tlv_length)) {
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_GetContainer(data->decoder, tlv_length);
+
+ success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, data->packetDictionary);
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ } else {
+ // raise and error
+ if (!ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, tlv_length)) {
+ // tlv_length goes beyond the decoder
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_TOO_LONG, __func__, __LINE__, ccnxCodecTlvDecoder_Position(data->decoder));
+ ccnxCodecTlvDecoder_SetError(data->decoder, error);
+ ccnxCodecError_Release(&error);
+ } else {
+ // not CCNxCodecSchemaV1Types_MessageType_ValidationAlg
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(data->decoder));
+ ccnxCodecTlvDecoder_SetError(data->decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+ }
+ }
+
+ return success;
+}
+
+static bool
+_decodeValidationPayload(_CCNxCodecSchemaV1Data *data)
+{
+ bool success = false;
+
+ if (ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, 4)) {
+ // what kind of message are we looking at?
+ // Note that this is based on the TLV container, not the fixed head PacketType
+ uint16_t tlv_type = ccnxCodecTlvDecoder_GetType(data->decoder);
+ uint16_t tlv_length = ccnxCodecTlvDecoder_GetLength(data->decoder);
+
+ if (tlv_type == CCNxCodecSchemaV1Types_MessageType_ValidationPayload &&
+ ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, tlv_length)) {
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_GetContainer(data->decoder, tlv_length);
+
+ success = ccnxCodecSchemaV1ValidationDecoder_DecodePayload(decoder, data->packetDictionary);
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ }
+ }
+
+ return success;
+}
+
+bool
+ccnxCodecSchemaV1PacketDecoder_Decode(CCNxCodecTlvDecoder *packetDecoder, CCNxTlvDictionary *packetDictionary)
+{
+ bool decodeSuccess = false;
+
+ _CCNxCodecSchemaV1Data data;
+
+ // we temporarily store this reference, but we do not destroy it. This
+ // is just to pass the reference down the decode chain, it is not
+ // stored beyond the immediate scope. Therefore, no reference acquired.
+ data.packetDictionary = packetDictionary;
+ data.decoder = packetDecoder;
+
+ if (ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data.decoder, data.packetDictionary)) {
+ if (_decodeOptionalHeaders(&data)) {
+ // Record the position we'd start the signature verification at
+ size_t signatureStartPosition = ccnxCodecTlvDecoder_Position(data.decoder);
+
+
+ // Mark the beginning of the ContentObject hash region.
+ CCNxWireFormatFacadeV1_Implementation.setContentObjectHashRegionStart(data.packetDictionary, signatureStartPosition);
+
+ if (_decodeMessage(&data)) {
+ // If there's anything else left, it must be the validation alg and payload
+ if (!ccnxCodecTlvDecoder_IsEmpty(data.decoder)) {
+ if (_decodeValidationAlg(&data)) {
+ // at this point, we've advanced to the end of the validation algorithm,
+ // that's where we would end signature verification
+ size_t signatureStopPosition = ccnxCodecTlvDecoder_Position(data.decoder);
+
+ CCNxWireFormatFacadeV1_Implementation.setProtectedRegionStart(data.packetDictionary, signatureStartPosition);
+ CCNxWireFormatFacadeV1_Implementation.setProtectedRegionLength(data.packetDictionary, signatureStopPosition - signatureStartPosition);
+
+ if (_decodeValidationPayload(&data)) {
+ decodeSuccess = true;
+ }
+ }
+ } else {
+ // nothing after the message, so that's a successful decode
+ decodeSuccess = true;
+ }
+
+ // Mark the length of the ContentObject hash region (to the end of the packet).
+ size_t contentObjectHashRegionLength = ccnxCodecTlvDecoder_Position(data.decoder) - signatureStartPosition;
+ CCNxWireFormatFacadeV1_Implementation.setContentObjectHashRegionLength(data.packetDictionary, contentObjectHashRegionLength);
+ }
+ }
+ }
+
+ return decodeSuccess;
+}
+
+bool
+ccnxCodecSchemaV1PacketDecoder_BufferDecode(PARCBuffer *packetBuffer, CCNxTlvDictionary *packetDictionary)
+{
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, packetDictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ return success;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h
new file mode 100755
index 00000000..9c1defd9
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_PacketDecoder.h
+ * @brief Decoder for the version 1 TLV Packet
+ *
+ * The Schema version 1 Dictionary is organized in containers: FixedHeader, OptionalHeaders, (Interest, ContentObject, Control), Verification.
+ *
+ * Each container is its own dictionary.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTlvDictionary *packetDictionary = ccnxTlvDictionary_Create();
+ * ccnxCodecSchemaV1PacketDecoder_Decode(packetBuffer, packetDictionary);
+ * // the fields in the packetDictionary are now set
+ * }
+ * @endcode
+ *
+ */
+
+#ifndef CCNxCodecSchemaV1_PacketDecoder_h
+#define CCNxCodecSchemaV1_PacketDecoder_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+
+/**
+ * Decode a packet in to a dictionary.
+ *
+ * The buffer should be set at the start of the fixed header. This call is equivalent
+ * to ccnxCodecSchemaV1PacketDecoder_Decode(), except it allocates and destroys a temporary
+ * CCNxCodecTlvDecoder.
+ *
+ * The dictionary will be filled in with all fields available in the packetBuffer.
+ *
+ * Caveat: there is no way to find out where the error was if returned "false"
+ *
+ * @param [in] buffer The packet buffer
+ * @param [in] packetDictionary The dictionary to fill in
+ *
+ * @return true Successful decode
+ * @return false There was an error somewhere
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+bool ccnxCodecSchemaV1PacketDecoder_BufferDecode(PARCBuffer *packetBuffer, CCNxTlvDictionary *packetDictionary);
+
+/**
+ * Decode in to in to a dictionary.
+ *
+ * The buffer should be set at the start of the fixed header.
+ *
+ * The dictionary will be filled in with all fields available in the packetDecoder.
+ *
+ * Caveat: there is no way to find out where the error was if returned "false"
+ *
+ * @param [in] buffer The packet buffer
+ * @param [in] packetDictionary The dictionary to fill in
+ *
+ * @return true Successful decode
+ * @return false There was an error somewhere
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+bool ccnxCodecSchemaV1PacketDecoder_Decode(CCNxCodecTlvDecoder *packetDecoder, CCNxTlvDictionary *packetDictionary);
+
+#endif // CCNxCodecSchemaV1_PacketDecoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c
new file mode 100755
index 00000000..bddd32d4
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <inttypes.h>
+
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h>
+
+#include <ccnx/common/internal/ccnx_InterestDefault.h>
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+#include <ccnx/common/internal/ccnx_WireFormatMessageInterface.h>
+
+// =====================================================
+// Private API
+
+static uint8_t
+_getHopLimit(CCNxTlvDictionary *packetDictionary)
+{
+ uint8_t hoplimit = (uint8_t) CCNxInterestDefault_HopLimit;
+
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT)) {
+ hoplimit = (uint8_t) ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT);
+ }
+ return hoplimit;
+}
+
+static uint8_t
+_getInterestReturnCode(CCNxTlvDictionary *packetDictionary)
+{
+ uint8_t returnCode = (uint8_t) 0;
+
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode)) {
+ returnCode =
+ (uint8_t) ccnxTlvDictionary_GetInteger(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode);
+ }
+ return returnCode;
+}
+
+/**
+ * Creates a fixed header from the given parameters and encodes in network byte order
+ *
+ * All parameters in host byte order.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-negative The total bytes appended to the encode buffer
+ * @return -1 An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static ssize_t
+_encodeFixedHeader(CCNxCodecTlvEncoder *fixedHeaderEncoder,
+ CCNxTlvDictionary *packetDictionary,
+ int packetType,
+ ssize_t headerLength,
+ ssize_t packetLength)
+{
+ CCNxCodecSchemaV1FixedHeader fixedHeader;
+ memset(&fixedHeader, 0, sizeof(fixedHeader));
+
+ fixedHeader.version = 1;
+ fixedHeader.packetType = packetType;
+ fixedHeader.packetLength = packetLength;
+ fixedHeader.headerLength = headerLength;
+
+ if ((packetType == CCNxCodecSchemaV1Types_PacketType_Interest) ||
+ (packetType == CCNxCodecSchemaV1Types_PacketType_InterestReturn)) {
+ CCNxCodecSchemaV1InterestHeader *interestHeader = (CCNxCodecSchemaV1InterestHeader *) &fixedHeader;
+ interestHeader->hopLimit = _getHopLimit(packetDictionary);
+ if (packetType == CCNxCodecSchemaV1Types_PacketType_InterestReturn) {
+ interestHeader->returnCode = _getInterestReturnCode(packetDictionary);
+ }
+ }
+
+ return ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(fixedHeaderEncoder, &fixedHeader);
+}
+
+static ssize_t
+_encodeOptionalHeaders(CCNxCodecTlvEncoder *optionalHeaderEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ // Optional Headers do not have a container, so just append them right to the buffer
+ size_t optionalHeadersLength = 0;
+ optionalHeadersLength = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(optionalHeaderEncoder, packetDictionary);
+ return optionalHeadersLength;
+}
+
+/**
+ * CPI payload is simply a dump of the PAYLOAD dictionary entry.
+ *
+ * There are no inner TLVs of this message, so it is not encoded like a normal message
+ * with a call to ccnxCodecSchemaV1MessageEncoder_Encode(). Rather it is written here.
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return non-negative The number of bytes appended to the buffer
+ * @return negative An error
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static ssize_t
+_encodeCPI(CCNxCodecTlvEncoder *cpiEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ // Optional Headers do not have a container, so just append them right to the buffer
+ size_t payloadLength = 0;
+
+ if (ccnxTlvDictionary_IsValueJson(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD)) {
+ PARCJSON *json = ccnxTlvDictionary_GetJson(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+ if (json) {
+ char *jsonString = parcJSON_ToCompactString(json);
+
+ payloadLength = strlen(jsonString);
+ ccnxCodecTlvEncoder_AppendRawArray(cpiEncoder, payloadLength, (uint8_t * ) jsonString);
+ parcMemory_Deallocate((void **) &jsonString);
+ }
+ } else {
+ PARCBuffer *payload = ccnxTlvDictionary_GetBuffer(packetDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+
+ payloadLength = parcBuffer_Remaining(payload);
+ uint8_t *overlay = parcBuffer_Overlay(payload, 0);
+ ccnxCodecTlvEncoder_AppendRawArray(cpiEncoder, payloadLength, overlay);
+ }
+ return payloadLength;
+}
+
+/**
+ * Encode the CCNx Message
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [out] packetTypePtr The type to use for the PacketType based on the message type
+ *
+ * @retval non-negative the bytes appended to the encoder
+ * @retval negative An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static ssize_t
+_encodeMessage(CCNxCodecTlvEncoder *packetEncoder, CCNxTlvDictionary *packetDictionary, CCNxCodecSchemaV1Types_PacketType *packetTypePtr)
+{
+ ssize_t startPosition = ccnxCodecTlvEncoder_Position(packetEncoder);
+ ssize_t innerLength = -1;
+
+ // what kind of message is it? need this to set the packetTypePtr
+
+ if (ccnxTlvDictionary_IsInterest(packetDictionary)) {
+ *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_Interest;
+ ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_Interest, 0);
+ innerLength = ccnxCodecSchemaV1MessageEncoder_Encode(packetEncoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsInterestReturn(packetDictionary)) {
+ *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_InterestReturn;
+ ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_Interest, 0);
+ innerLength = ccnxCodecSchemaV1MessageEncoder_Encode(packetEncoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsContentObject(packetDictionary)) {
+ *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_ContentObject;
+ ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_ContentObject, 0);
+ innerLength = ccnxCodecSchemaV1MessageEncoder_Encode(packetEncoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsControl(packetDictionary)) {
+ *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_Control;
+ ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_Control, 0);
+ innerLength = _encodeCPI(packetEncoder, packetDictionary);
+ } else if (ccnxTlvDictionary_IsManifest(packetDictionary)) {
+ *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_ContentObject;
+ ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_Manifest, 0);
+ innerLength = ccnxCodecSchemaV1MessageEncoder_Encode(packetEncoder, packetDictionary);
+ }
+
+ if (innerLength >= 0) {
+ // For a 0 length message, we do not backup and erase the TLV container.
+ ccnxCodecTlvEncoder_SetContainerLength(packetEncoder, startPosition, innerLength);
+ ssize_t endPosition = ccnxCodecTlvEncoder_Position(packetEncoder);
+ innerLength = endPosition - startPosition;
+ } else {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(packetEncoder));
+ ccnxCodecTlvEncoder_SetError(packetEncoder, error);
+ ccnxCodecError_Release(&error);
+ }
+
+ return innerLength;
+}
+
+static ssize_t
+_encodeValidationAlg(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t innerLength = 0;
+
+ // There must be a CryptoSuite in the packet to sign it.
+ // Temporary exception for Content Objects, which are all signed if the codec has a signer.
+ if (ccnxValidationFacadeV1_HasCryptoSuite(packetDictionary) || ccnxTlvDictionary_IsContentObject(packetDictionary)) {
+ ssize_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_MessageType_ValidationAlg, 0);
+ innerLength = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, packetDictionary);
+
+ if (innerLength == 0) {
+ // backup and erase the container
+ ccnxCodecTlvEncoder_SetPosition(encoder, startPosition);
+ } else if (innerLength >= 0) {
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, innerLength);
+ ssize_t endPosition = ccnxCodecTlvEncoder_Position(encoder);
+ return endPosition - startPosition;
+ }
+ }
+
+ return innerLength;
+}
+
+static ssize_t
+_encodeValidationPayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_MessageType_ValidationPayload, 0);
+ ssize_t innerLength = ccnxCodecSchemaV1ValidationEncoder_EncodePayload(encoder, packetDictionary);
+
+ if (innerLength == 0) {
+ // backup and erase the container
+ ccnxCodecTlvEncoder_SetPosition(encoder, startPosition);
+ } else if (innerLength > 0) {
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, innerLength);
+ ssize_t endPosition = ccnxCodecTlvEncoder_Position(encoder);
+ return endPosition - startPosition;
+ }
+
+ return innerLength;
+}
+
+// =====================================================
+// Public API
+
+CCNxCodecNetworkBufferIoVec *
+ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(CCNxTlvDictionary *packetDictionary, PARCSigner *signer)
+{
+ CCNxCodecNetworkBufferIoVec *outputBuffer = NULL;
+
+ CCNxCodecTlvEncoder *packetEncoder = ccnxCodecTlvEncoder_Create();
+
+ if (signer) {
+// ccnxCodecTlvEncoder_SetSigner(packetEncoder, signer);
+ }
+
+ ssize_t encodedLength = ccnxCodecSchemaV1PacketEncoder_Encode(packetEncoder, packetDictionary);
+ if (encodedLength > 0) {
+ ccnxCodecTlvEncoder_Finalize(packetEncoder);
+ outputBuffer = ccnxCodecTlvEncoder_CreateIoVec(packetEncoder);
+ }
+
+ trapUnexpectedStateIf(encodedLength < 0 && !ccnxCodecTlvEncoder_HasError(packetEncoder),
+ "Got error length but no error set");
+
+ assertFalse(ccnxCodecTlvEncoder_HasError(packetEncoder), "ENCODING ERROR")
+ {
+ printf("ERROR: %s\n", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(packetEncoder)));
+ ccnxTlvDictionary_Display(packetDictionary, 3);
+ }
+
+ ccnxCodecTlvEncoder_Destroy(&packetEncoder);
+
+ // return a reference counted copy so it won't be destroyed by ccnxCodecTlvEncoder_Destroy
+ return outputBuffer;
+}
+
+ssize_t
+ccnxCodecSchemaV1PacketEncoder_Encode(CCNxCodecTlvEncoder *packetEncoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = -1;
+
+ // We will need to go back and fixedup the headers
+ ssize_t fixedHeaderPosition = ccnxCodecTlvEncoder_Position(packetEncoder);
+ ssize_t fixedHeaderLength = _encodeFixedHeader(packetEncoder, packetDictionary, -1, 0, 0);
+
+ ssize_t optionalHeadersLength = _encodeOptionalHeaders(packetEncoder, packetDictionary);
+
+ if (optionalHeadersLength >= 0) {
+ ccnxCodecTlvEncoder_MarkSignatureStart(packetEncoder);
+
+ CCNxCodecSchemaV1Types_PacketType messageType = -1;
+
+ ssize_t messageLength = _encodeMessage(packetEncoder, packetDictionary, &messageType);
+
+ if (messageLength >= 0) {
+ // validation is optional, so it's ok if its 0 length
+ ssize_t validationAlgLength = _encodeValidationAlg(packetEncoder, packetDictionary);
+ ssize_t validationPayloadLength = 0;
+ if (validationAlgLength > 0) {
+ ccnxCodecTlvEncoder_MarkSignatureEnd(packetEncoder);
+
+ validationPayloadLength = _encodeValidationPayload(packetEncoder, packetDictionary);
+ }
+
+ if (validationAlgLength >= 0 && validationPayloadLength >= 0) {
+ // now fix up the fixed header
+ size_t endPosition = ccnxCodecTlvEncoder_Position(packetEncoder);
+
+ size_t headerLength = fixedHeaderLength + optionalHeadersLength;
+ size_t packetLength = headerLength + messageLength + validationAlgLength + validationPayloadLength;
+
+ // Will this work for InterestReturn? As long as _encodeMessage returns InterestReturn it
+ // will be ok.
+ int packetType = messageType;
+
+ ccnxCodecTlvEncoder_SetPosition(packetEncoder, fixedHeaderPosition);
+ _encodeFixedHeader(packetEncoder, packetDictionary, packetType, headerLength, packetLength);
+ ccnxCodecTlvEncoder_SetPosition(packetEncoder, endPosition);
+ length = endPosition - fixedHeaderPosition;
+
+ trapUnexpectedStateIf(packetLength != length, "packet length %zu not equal to measured length %zd", packetLength, length);
+ }
+ }
+ }
+
+ return length;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h
new file mode 100755
index 00000000..c83f165f
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_PacketEncoder.h
+ * @brief Encoder for the version 1 TLV Packet
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ *
+ */
+
+#ifndef CCNxCodecSchemaV1_PacketEncoder_h
+#define CCNxCodecSchemaV1_PacketEncoder_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_Signer.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/codec/ccnxCodec_EncodingBuffer.h>
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+
+/**
+ * Encode the packetDictionary to wire format
+ *
+ * Will only use the PacketType from FixedHeader in the dictionary, if provided. The packet Version is fixed at "1",
+ * the PayloadLength and HeaderLength are calculated. If the FixedHeaderDictionary is not provided, the
+ * PacketType is inferred from the type of CCNx message.
+ *
+ * The signer is not stored beyond the call to DictionaryEncode.
+ * If the dictionary already has a ValidationAlg and ValidationPayload, those are used, not the Signer.
+ * Otherwise, if the signer is not null, it is used to sign the wire format.
+ *
+ * @param [in] packetDictionary The dictionary representation of the packet to encode
+ * @param [in] signer If not NULL will be used to sign the wire format
+ *
+ * @retval non-null An IoVec that can be written to the network
+ * @retval null an error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxCodecNetworkBufferIoVec *ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(CCNxTlvDictionary *packetDictionary, PARCSigner *signer);
+
+/**
+ * Encode a packetDictionary to wire format.
+ *
+ * Will only use the PacketType from FixedHeader in the dictionary, if provided. The packet Version is fixed at "1",
+ * the PayloadLength and HeaderLength are calculated. If the FixedHeaderDictionary is not provided, the
+ * PacketType is inferred from the type of CCNx message.
+ *
+ * You must use ccnxCodecTlvEncoder_SetSigner(signer) if you require a signature or MAC on the packet.
+ *
+ * @param [in] packetEncoder A TLV packet will be appended to the encoder
+ * @param [in] packetDictionary The dictionary representation of the packet to encode
+ *
+ * @retval non-negative The total bytes appended to the encode buffer
+ * @retval -1 An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1PacketEncoder_Encode(CCNxCodecTlvEncoder *packetEncoder, CCNxTlvDictionary *packetDictionary);
+
+#endif // CCNxCodecSchemaV1_PacketEncoder_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.c
new file mode 100644
index 00000000..72e1ce3e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <LongBow/runtime.h>
+#include <ccnx/common/ccnx_PayloadType.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+CCNxTlvDictionary *
+ccnxCodecSchemaV1TlvDictionary_CreateInterest(void)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+ ccnxTlvDictionary_SetMessageType_Interest(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ return dictionary;
+}
+
+CCNxTlvDictionary *
+ccnxCodecSchemaV1TlvDictionary_CreateContentObject(void)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+ ccnxTlvDictionary_SetMessageType_ContentObject(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ return dictionary;
+}
+
+CCNxTlvDictionary *
+ccnxCodecSchemaV1TlvDictionary_CreateManifest(void)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+ ccnxTlvDictionary_SetMessageType_Manifest(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+
+ return dictionary;
+}
+
+CCNxTlvDictionary *
+ccnxCodecSchemaV1TlvDictionary_CreateControl(void)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+ ccnxTlvDictionary_SetMessageType_Control(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ return dictionary;
+}
+
+CCNxTlvDictionary *
+ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn(void)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+ ccnxTlvDictionary_SetMessageType_InterestReturn(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ return dictionary;
+}
+
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h
new file mode 100755
index 00000000..e76492b6
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_TlvDictionary.h
+ * @brief <#Brief Description#>
+ *
+ * Used as keys to the CCNxTlvDictionary for the version 1 schema
+ *
+ */
+
+#ifndef libccnx_ccnx_TlvDictionary_SchemaV1_h
+#define libccnx_ccnx_TlvDictionary_SchemaV1_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+/**
+ * @typedef CCNxCodecSchemaV1TlvDictionary_CryptoSuite
+ * @abstract The ValidationAlgorithm Type.
+ * @constant <#name#> <#description#>
+ * @discussion These are the wire-format values for the ValidationAlgorithm type. The values
+ * specified follow from the CCNx Messages RFC.
+ *
+ * It is not the same as the value stored in CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE,
+ * which is of type PARCCryptoSuite.
+ */
+typedef enum rta_tlv_schema_v1_crypto_suite {
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C = 2,
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256 = 4,
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256 = 6,
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite_EcSecp256K1 = 7,
+} CCNxCodecSchemaV1TlvDictionary_CryptoSuite;
+
+/**
+ * @typedef <#CCNBHeaderType#>
+ * @abstract <#Abstract#>
+ * @constant CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat The off-the-wire packet or a pre-encoded packet
+ * @discussion
+ * The WireFormat header is a ficticious header for holding the off-the-wire packet received
+ * from the network or to send a pre-encoded packet down through the stack.
+ *
+ * The Forwarder header is a ficticious header for holding special forwarder control block. The
+ * forwarder control block, on ingress, contains information about where a packet arrived. On
+ * egress, it contains information about how the packet should be transmitted, such as restricting
+ * it to a specific egress interface.
+ *
+ * The protected region extent is used to determine they byte range used for verification.
+ */
+
+
+typedef enum rta_tlv_schema_v1_headers_fastarray {
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_TransportStack = 0, /**< Array element 0 is used by RTA Transport stack */
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader = 1,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG = 2,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG = 3,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat = 4,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_Forwarder = 5,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime = 6,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime = 7,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedStart = 8, /**< Fictitious header for Protected Region Extent */
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedLength = 9, /**< Fictitious header for Protected Region length */
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionStart = 10, /**< Fictitious header for CO Hash Region Extent */
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionLength = 11, /**< Fictitious header for CO Hash Region length */
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode = 12,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel = 13,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END = 14
+} CCNxCodecSchemaV1TlvDictionary_HeadersFastArray;
+
+/**
+ * The ValidationFastArray are fields that may appear in the Validation Algorithm and the Validation Payload field.
+ *
+ * Note that the ValidationFastArray_CRYPTO_SUITE is always expressed in terms of PARCCryptoSuite.
+ */
+typedef enum rta_tlv_schema_v1_validation_fastarray {
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 0,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 1, // PARCCryptoSuite value
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 2,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 3,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 4,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 5,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 6,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 7,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 8,
+ CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 9
+} CCNxCodecSchemaV1TlvDictionary_ValidationFastArray;
+
+
+/**
+ * The MessageFastArray are fields that may appear in the body of a CCNx message (Interest, Content Object, Control).
+ *
+ * The Hop Limit is part of the MessageFastArray even though it appears in the FixedHeader. It is treated like a property
+ * of the Interest.
+ */
+typedef enum rta_tlv_schema_v1_message_fastarray {
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 0,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 1,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 2,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 4,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 5, /***< Virtual field */
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 6,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 7,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 8,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HASH_GROUP = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 9,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_DATA_POINTER = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 10,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_MANIFEST_POINTER = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 11,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 12
+} CCNxCodecSchemaV1TlvDictionary_MessageFastArray;
+
+//const int CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel = CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END + 1;
+
+/**
+ * Each TLV container can have custom types in it, so each container has a "list"
+ * Organization Extensions go here.
+ */
+typedef enum rta_tlv_schema_v1_lists {
+ CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS = 0,
+ CCNxCodecSchemaV1TlvDictionary_Lists_MESSAGE_LIST = 1,
+ CCNxCodecSchemaV1TlvDictionary_Lists_VALIDATION_ALG_LIST = 4,
+ CCNxCodecSchemaV1TlvDictionary_Lists_VALIDATION_PAYLOAD_LIST = 5,
+ CCNxCodecSchemaV1TlvDictionary_Lists_HASH_GROUP_LIST = 6,
+ CCNxCodecSchemaV1TlvDictionary_Lists_END = 7
+} CCNxCodecSchemaV1TlvDictionary_Lists;
+
+/**
+ * Creates an empty Interest dictionary
+ *
+ * The dictionary schema will be V1 and the dictionary type will be Interest. No other
+ * fields are pre-populated.
+ *
+ * @retval non-null An allocated Dictionary of type Interest
+ * @retval null An error (likely no memory)
+ *
+ * Example:
+ * @code
+ * {
+ * // in a decoder
+ * if (messageType == _DecoderTlvType_Interest) {
+ * CCNxTlvDictionary *interest = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ * // decode the rest of the packet
+ * return interest;
+ * }
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateInterest(void);
+
+/**
+ * Creates an empty Content Object dictionary
+ *
+ * The dictionary schema will be V1 and the dictionary type will be Content Object. No other
+ * fields are pre-populated.
+ *
+ * @retval non-null An allocated Dictionary of type Content Object
+ * @retval null An error (likely no memory)
+ *
+ * Example:
+ * @code
+ * {
+ * // in a decoder
+ * if (messageType == _DecoderTlvType_ContentObject) {
+ * CCNxTlvDictionary *object = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ * // decode the rest of the packet
+ * return object;
+ * }
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateContentObject(void);
+
+/**
+ * Creates an empty Manifest dictionary
+ *
+ * The dictionary schema will be V1 and the dictionary type will be Content Object. The
+ * PayloadType will be set to CCNxPayloadType_MANIFEST. No other fields are pre-populated.
+ *
+ * @retval non-null An allocated Dictionary of type Manifest
+ * @retval null An error (likely no memory)
+ *
+ * Example:
+ * @code
+ * {
+ * // in a decoder
+ * if (messageType == _DecoderTlvType_Manifest) {
+ * CCNxTlvDictionary *object = ccnxCodecSchemaV1TlvDictionary_Manifest();
+ * // decode the rest of the packet
+ * return object;
+ * }
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateManifest(void);
+
+/**
+ * Creates an empty Control dictionary
+ *
+ * The dictionary schema will be V1 and the dictionary type will be Control. No other
+ * fields are pre-populated.
+ *
+ * @retval non-null An allocated Dictionary of type Control
+ * @retval null An error (likely no memory)
+ *
+ * Example:
+ * @code
+ * {
+ * // in a decoder
+ * if (messageType == _DecoderTlvType_Control) {
+ * CCNxTlvDictionary *control = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+ * // decode the rest of the packet
+ * return control;
+ * }
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateControl(void);
+
+/**
+ * Creates an empty InterestReturn dictionary
+ *
+ * The dictionary schema will be V1 and the dictionary type will be InterestReturn. No other
+ * fields are pre-populated.
+ *
+ * @retval non-null An allocated Dictionary of type InterestReturn
+ * @retval null An error (likely no memory)
+ *
+ * Example:
+ * @code
+ * {
+ * // in a decoder
+ * if (messageType == _DecoderTlvType_InterestReturn) {
+ * CCNxTlvDictionary *interestReturn = ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn();
+ * // decode the rest of the packet
+ * return interestReturn;
+ * }
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn(void);
+#endif // libccnx_ccnx_TlvDictionary_SchemaV1_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h
new file mode 100755
index 00000000..1c50eebc
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_Types.h
+ * @brief Common definitions for Schema version 1
+ *
+ * Defines the TLV "type" values for each field
+ *
+ */
+
+#ifndef TransportRTA_ccnxCodecSchemaV1_Types_h
+#define TransportRTA_ccnxCodecSchemaV1_Types_h
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_PacketType
+ * @abstract The values used in the PacketType field of the Fixed Header
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_packet_type {
+ CCNxCodecSchemaV1Types_PacketType_Interest = 0x00,
+ CCNxCodecSchemaV1Types_PacketType_ContentObject = 0x01,
+ CCNxCodecSchemaV1Types_PacketType_InterestReturn = 0x02,
+ CCNxCodecSchemaV1Types_PacketType_Control = 0xA4,
+} CCNxCodecSchemaV1Types_PacketType;
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_MessageType
+ * @abstract The values used in the MessageType field of the CCNx Message body
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_message_type {
+ CCNxCodecSchemaV1Types_MessageType_Interest = 0x0001,
+ CCNxCodecSchemaV1Types_MessageType_ContentObject = 0x0002,
+ CCNxCodecSchemaV1Types_MessageType_ValidationAlg = 0x0003,
+ CCNxCodecSchemaV1Types_MessageType_ValidationPayload = 0x0004,
+ CCNxCodecSchemaV1Types_MessageType_Manifest = 0x0006,
+ CCNxCodecSchemaV1Types_MessageType_Control = 0xBEEF,
+} CCNxCodecSchemaV1Types_MessageType;
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_OptionalHeadersTypes
+ * @abstract The well-known keys for the hop-by-hop headers
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_optional_headers_types {
+ CCNxCodecSchemaV1Types_OptionalHeaders_InterestLifetime = 0x0001,
+ CCNxCodecSchemaV1Types_OptionalHeaders_RecommendedCacheTime = 0x0002,
+ CCNxCodecSchemaV1Types_OptionalHeaders_PathLabel = 0x0003,
+ CCNxCodecSchemaV1Types_OptionalHeaders_InterestFragment = 0x0004,
+ CCNxCodecSchemaV1Types_OptionalHeaders_ContentObjectFragment = 0x0005,
+} CCNxCodecSchemaV1Types_OptionalHeaders;
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_PayloadType
+ * @abstract The values of the PayloadType field
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_payloadtype_types {
+ CCNxCodecSchemaV1Types_PayloadType_Data = 0,
+ CCNxCodecSchemaV1Types_PayloadType_Key = 1,
+ CCNxCodecSchemaV1Types_PayloadType_Link = 2,
+} CCNxCodecSchemaV1Types_PayloadType;
+
+// ==================================================
+// Fields in a Message Object
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_MessageTypes
+ * @abstract The well-known types inside the CCNxMessage
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_ccnxmessage_types {
+ CCNxCodecSchemaV1Types_CCNxMessage_Name = 0x0000,
+ CCNxCodecSchemaV1Types_CCNxMessage_Payload = 0x0001,
+ CCNxCodecSchemaV1Types_CCNxMessage_KeyIdRestriction = 0x0002,
+ CCNxCodecSchemaV1Types_CCNxMessage_ContentObjectHashRestriction = 0x0003,
+ CCNxCodecSchemaV1Types_CCNxMessage_PayloadType = 0x0005,
+ CCNxCodecSchemaV1Types_CCNxMessage_ExpiryTime = 0x0006,
+ CCNxCodecSchemaV1Types_CCNxMessage_HashGroup = 0x0007,
+ CCNxCodecSchemaV1Types_CCNxMessage_EndChunkNumber = 0x0019,
+} CCNxCodecSchemaV1Types_CCNxMessage;
+
+typedef enum rta_tlv_schema_v1_ccnxmanifest_hashgroup_types {
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata = 0x0001,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer = 0x0002,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroup_ManifestPointer = 0x0003,
+} CCNxCodecSchemaV1Types_CCNxManifestHashGroup;
+
+typedef enum rta_tlv_schema_v1_ccnxmanifest_hashgroup_metadata_types {
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator = 0x0000,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize = 0x0001,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize = 0x0002,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize = 0x0003,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight = 0x0004,
+ CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256 = 0x0005,
+} CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata;
+
+// ==================================================
+// Fields in a Validation Algorithm
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_ValidationAlg
+ * @abstract The well-known keys for the ContentObject
+ * @constant <#name#> <#description#>
+ * @discussion the CCNxCodecSchemaV1Types_ValidationAlg values for the crypto suites must be the same as CCNxCodecSchemaV1Types_CryptoSuiteType
+ */
+typedef enum rta_tlv_schema_v1_validation_alg {
+ CCNxCodecSchemaV1Types_ValidationAlg_CRC32C = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, // 0x0002
+ CCNxCodecSchemaV1Types_ValidationAlg_HMAC_SHA256 = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, // 0x0004
+ CCNxCodecSchemaV1Types_ValidationAlg_RSA_SHA256 = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, // 0x0006
+ CCNxCodecSchemaV1Types_ValidationAlg_EC_SECP_256K1 = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_EcSecp256K1, // 0x0007
+
+ CCNxCodecSchemaV1Types_ValidationAlg_KeyId = 0x0009,
+ CCNxCodecSchemaV1Types_ValidationAlg_PublicKey = 0x000B,
+ CCNxCodecSchemaV1Types_ValidationAlg_Cert = 0x000C,
+ CCNxCodecSchemaV1Types_ValidationAlg_KeyName = 0x000E,
+ CCNxCodecSchemaV1Types_ValidationAlg_SigTime = 0x000F,
+} CCNxCodecSchemaV1Types_ValidationAlg;
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_Link
+ * @abstract The well-known keys for the LINK body
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_link_types {
+ CCNxCodecSchemaV1Types_Link_Name = 0x0000,
+ CCNxCodecSchemaV1Types_Link_KeyIdRestriction = 0x0001,
+ CCNxCodecSchemaV1Types_Link_ContentObjectHashRestriction = 0x0002,
+} CCNxCodecSchemaV1Types_Link;
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_HashGroup
+ * @abstract The well-known keys for the Manifest HashGroup.
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_link_hash_group {
+ CCNxCodecSchemaV1Types_HashGroup_Metadata = 0x0001,
+ CCNxCodecSchemaV1Types_HashGroup_DataPointer = 0x0002,
+ CCNxCodecSchemaV1Types_HashGroup_ManifestPointer = 0x0003
+} CCNxCodecSchemaV1Types_HashGroup;
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_HashGroup
+ * @abstract The well-known keys for the Manifest HashGroup.
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_link_hash_group_metadata {
+ CCNxCodecSchemaV1Types_HashGroup_Locator = 0x0000,
+ CCNxCodecSchemaV1Types_HashGroup_ExternalMetadata = 0x0001,
+ CCNxCodecSchemaV1Types_HashGroup_BlockSize = 0x0002,
+ CCNxCodecSchemaV1Types_HashGroup_OverallDataSize = 0x0003,
+ CCNxCodecSchemaV1Types_HashGroup_OverallDataSha256 = 0x0004,
+} CCNxCodecSchemaV1Types_HashGroupMetadata;
+
+// ==================================================
+// Interest Return
+
+/**
+ * @typedef CCNxCodecSchemaV1Types_InterestReturnCode
+ * @abstract The values of the InterestReturn ReturnCode field
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_interestreturncode_types {
+ CCNxCodecSchemaV1Types_InterestReturnCode_NoRoute = 0x01,
+ CCNxCodecSchemaV1Types_InterestReturnCode_HopLimitExceeded = 0x02,
+ CCNxCodecSchemaV1Types_InterestReturnCode_NoResources = 0x03,
+ CCNxCodecSchemaV1Types_InterestReturnCode_PathError = 0x04,
+ CCNxCodecSchemaV1Types_InterestReturnCode_Prohibited = 0x05,
+ CCNxCodecSchemaV1Types_InterestReturnCode_Congestion = 0x06,
+ CCNxCodecSchemaV1Types_InterestReturnCode_MTUTooLarge = 0x07,
+} CCNxCodecSchemaV1Types_InterestReturnCode;
+
+// ==================================================
+// Hash function types
+/**
+ * @typedef CCNxCodecSchemaV1Types_HashTypes
+ * @abstract The values of the InterestReturn ReturnCode field
+ * @constant <#name#> <#description#>
+ * @discussion <#Discussion#>
+ */
+typedef enum rta_tlv_schema_v1_hash_types {
+ CCNxCodecSchemaV1Types_HashType_SHA256 = 0x01,
+ CCNxCodecSchemaV1Types_HashType_SHA512 = 0x02,
+ CCNxCodecSchemaV1Types_HashType_App
+} CCNxCodecSchemaV1Types_HashType;
+
+#endif //TransportRTA_ccnxCodecSchemaV1_Types_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.c
new file mode 100755
index 00000000..0524bcfa
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h>
+
+static bool
+_decodeKeyName(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+{
+ // At this point, the decoder should point to the 1st byte of the "value" of the (type, length) continer.
+ // This is defined as a CCNxLink
+
+ bool success = false;
+
+ // this will set the decoder error if it fails.
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, length);
+ if (link != NULL) {
+ const CCNxName *name = ccnxLink_GetName(link);
+ if (name != NULL) {
+ success = ccnxTlvDictionary_PutName(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME, name);
+
+ if (success) {
+ PARCBuffer *keyid = ccnxLink_GetKeyID(link);
+ if (keyid) {
+ ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID, keyid);
+ }
+
+ PARCBuffer *hash = ccnxLink_GetContentObjectHash(link);
+ if (hash) {
+ ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH, hash);
+ }
+ }
+ }
+
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+
+ ccnxLink_Release(&link);
+ }
+
+ return success;
+}
+
+static bool
+_decodeAlgParametersType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+{
+ bool success = false;
+ switch (type) {
+ case CCNxCodecSchemaV1Types_ValidationAlg_Cert:
+ success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT);
+ break;
+
+ case CCNxCodecSchemaV1Types_ValidationAlg_KeyId:
+ success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID);
+ break;
+
+ case CCNxCodecSchemaV1Types_ValidationAlg_KeyName:
+ // The "value" is a link
+ success = _decodeKeyName(decoder, packetDictionary, type, length);
+ break;
+
+ case CCNxCodecSchemaV1Types_ValidationAlg_SigTime:
+ // This is a time, so put it as an Integer
+ success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME);
+ break;
+
+ case CCNxCodecSchemaV1Types_ValidationAlg_PublicKey:
+ success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY);
+ break;
+
+ default: {
+ // if we do not know the TLV type, put it in this container's unknown list
+ success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_Lists_VALIDATION_ALG_LIST);
+ }
+ break;
+ }
+
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+ return success;
+}
+
+/**
+ * Called by _decodeAlgType() via ccnxCodecTlvUtilities_DecodeSubcontainer() to decode the
+ * algorithm specific parameters
+ */
+static bool
+_decodeAlgParameters(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ return ccnxCodecTlvUtilities_DecodeContainer(decoder, packetDictionary, _decodeAlgParametersType);
+}
+
+static bool
+_decodeAlgType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+{
+ bool success = false;
+
+ PARCCryptoSuite parcSuite;
+ bool match = ccnxCodecSchemaV1CryptoSuite_TlvToParc((CCNxCodecSchemaV1TlvDictionary_CryptoSuite) type, &parcSuite);
+
+ if (match) {
+ success = ccnxTlvDictionary_PutInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, parcSuite);
+
+ if (success) {
+ success = ccnxCodecTlvUtilities_DecodeSubcontainer(decoder, packetDictionary, type, length, _decodeAlgParameters);
+ }
+ } else {
+ // if we do not know the TLV type, put it in this container's unknown list
+ success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_Lists_VALIDATION_ALG_LIST);
+ }
+
+ if (!success) {
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder));
+ ccnxCodecTlvDecoder_SetError(decoder, error);
+ ccnxCodecError_Release(&error);
+ }
+ return success;
+}
+
+// ==================
+// Public API
+
+bool
+ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ return ccnxCodecTlvUtilities_DecodeContainer(decoder, packetDictionary, _decodeAlgType);
+}
+
+
+bool
+ccnxCodecSchemaV1ValidationDecoder_DecodePayload(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ bool success = false;
+ // A 0-length payload is treaded like an error
+ size_t remaining = ccnxCodecTlvDecoder_Remaining(decoder);
+ if (remaining > 0) {
+ PARCBuffer *payload = ccnxCodecTlvDecoder_GetValue(decoder, remaining);
+ success = ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, payload);
+ parcBuffer_Release(&payload);
+ }
+ return success;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h
new file mode 100755
index 00000000..c5d5a42c
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_ValidationDecoder.h
+ * @brief Decode the validation algorithm and payload
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef __CCNx_Common__ccnxCodecSchemaV1_ValidationDecoder__
+#define __CCNx_Common__ccnxCodecSchemaV1_ValidationDecoder__
+
+#include <stdbool.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+
+/**
+ * The decode the validation algorithm
+ *
+ * The decoder should point to byte 0 of the valdiation algorithm "value"
+ *
+ * The results are put in the provided dictionary.
+ * It is an error if the "value" does not extend to the end of
+ * the decoder.
+ *
+ * @param [in] decoder The decoder to parse
+ * @param [in] packetDictionary The results go directly in to the provided dictionary.
+ *
+ * @return true Fully parsed, no errors
+ * @return false Error decoding, decoder is left pointing to the first byte of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary);
+
+/**
+ * The decode the validation payload
+ *
+ * The decoder should point to byte 0 of the valdiation payload "value"
+ * The payload is an opaque block, so this function will just put the "value" in to the proper
+ * dictionary location. There's no real parsing.
+ *
+ * @param [in] decoder The decoder to parse
+ * @param [in] packetDictionary The results go directly in to the provided dictionary.
+ *
+ * @return true Fully parsed, no errors
+ * @return false Error decoding, decoder is left pointing to the first byte of the error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxCodecSchemaV1ValidationDecoder_DecodePayload(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary);
+
+#endif /* defined(__CCNx_Common__ccnxCodecSchemaV1_ValidationDecoder__) */
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.c
new file mode 100755
index 00000000..f7ad00aa
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <sys/time.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h>
+
+static ssize_t
+_encodeKeyId(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID);
+ if (keyid) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_ValidationAlg_KeyId, keyid);
+ }
+ return length;
+}
+
+static ssize_t
+_encodePublicKey(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCBuffer *key = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY);
+ if (key) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_ValidationAlg_PublicKey, key);
+ }
+ return length;
+}
+
+static ssize_t
+_encodeCertificate(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ PARCBuffer *cert = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT);
+ if (cert) {
+ length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_ValidationAlg_Cert, cert);
+ }
+ return length;
+}
+
+/**
+ * If there is a CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME entry in the dictionary, look up the
+ * optional keyid and hash restrictions, create a CCNxLink, then encode the Link.
+ */
+static ssize_t
+_encodeKeyName(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ CCNxName *keyname = ccnxTlvDictionary_GetName(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME);
+ if (keyname) {
+ PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID);
+ PARCBuffer *hash = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH);
+ CCNxLink *link = ccnxLink_Create(keyname, keyid, hash);
+
+ size_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_ValidationAlg_KeyName, 0);
+ ssize_t innerLength = ccnxCodecSchemaV1LinkCodec_Encode(encoder, link);
+
+ if (innerLength == 0) {
+ // backup and erase the container
+ ccnxCodecTlvEncoder_SetPosition(encoder, startPosition);
+ } else if (innerLength > 0) {
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, innerLength);
+ ssize_t endPosition = ccnxCodecTlvEncoder_Position(encoder);
+ length = endPosition - startPosition;
+ } else {
+ // an error signal
+ length = innerLength;
+ }
+
+ ccnxLink_Release(&link);
+ }
+ return length;
+}
+
+/**
+ * If a time is not provided, use the current time
+ */
+static ssize_t
+_encodeSignatureTime(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+
+ bool haveSignTime = false;
+ uint64_t signTime = 0;
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME)) {
+ haveSignTime = true;
+ signTime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME);
+ } else {
+ // if we have a signer and with a signature algorithm, create the signing time
+ PARCSigner *signer = ccnxCodecTlvEncoder_GetSigner(encoder);
+ if (signer) {
+ PARCSigningAlgorithm alg = parcSigner_GetSigningAlgorithm(signer);
+ if (alg != PARCSigningAlgortihm_NULL && alg != PARCSigningAlgorithm_UNKNOWN) {
+ // We will generate a signature, so generate a signing time
+
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ // convert to milli-seconds
+ signTime = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+ haveSignTime = true;
+ }
+ }
+ }
+
+ if (haveSignTime) {
+ length = ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_ValidationAlg_SigTime, signTime);
+ }
+
+ return length;
+}
+
+static ssize_t
+_encodeAlgParameters(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ ssize_t result;
+
+ result = _encodeKeyId(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodePublicKey(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeCertificate(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeKeyName(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ result = _encodeSignatureTime(encoder, packetDictionary);
+ if (result < 0) {
+ return result;
+ }
+ length += result;
+
+ return length;
+}
+
+ssize_t
+ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+ bool haveCryptoSuite = false;
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite suite;
+
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE)) {
+ // try from dictionary
+
+ PARCCryptoSuite parcSuite = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+
+ haveCryptoSuite = ccnxCodecSchemaV1CryptoSuite_ParcToTlv(parcSuite, &suite);
+ } else if (ccnxTlvDictionary_IsContentObject(packetDictionary)) {
+ // deduce from the signer
+
+ PARCSigner *signer = ccnxCodecTlvEncoder_GetSigner(encoder);
+ if (signer != NULL) {
+ PARCCryptoHashType hashType = parcSigner_GetCryptoHashType(signer);
+ PARCSigningAlgorithm signAlg = parcSigner_GetSigningAlgorithm(signer);
+
+ if (ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv(signAlg, hashType, &suite)) {
+ haveCryptoSuite = true;
+ }
+ }
+ }
+
+ if (haveCryptoSuite) {
+ // write the TL container then encode any enclosed TLVs
+ ssize_t startPosition = ccnxCodecTlvEncoder_Position(encoder);
+
+ ccnxCodecTlvEncoder_AppendContainer(encoder, suite, 0);
+ ssize_t innerLength = _encodeAlgParameters(encoder, packetDictionary);
+
+ // 0 inner length is acceptable
+ if (innerLength >= 0) {
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, innerLength);
+ ssize_t endPosition = ccnxCodecTlvEncoder_Position(encoder);
+ length = endPosition - startPosition;
+ } else {
+ // an error signal
+ length = innerLength;
+ }
+ }
+ return length;
+}
+
+ssize_t
+ccnxCodecSchemaV1ValidationEncoder_EncodePayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary)
+{
+ ssize_t length = 0;
+
+ if (!ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD)) {
+ // try to compute a signature
+
+ // If signer is NULL, then no signature is genearted
+ PARCSigner *signer = ccnxCodecTlvEncoder_GetSigner(encoder);
+ if (signer != NULL) {
+ // user did not give us one, so fill it in
+ PARCSignature *signature = ccnxCodecTlvEncoder_ComputeSignature(encoder);
+ PARCBuffer *sigbits = parcSignature_GetSignature(signature);
+
+ // this creates its own reference to sigbits
+ ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, sigbits);
+
+ // this will release our hold on sigbitsElastic and sigbits.
+ parcSignature_Release(&signature);
+ }
+ }
+
+ PARCBuffer *sigbits = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+ if (sigbits) {
+ size_t remaining = parcBuffer_Remaining(sigbits);
+ uint8_t *overlay = parcBuffer_Overlay(sigbits, 0);
+ length = ccnxCodecTlvEncoder_AppendRawArray(encoder, remaining, overlay);
+ }
+
+ return length;
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h
new file mode 100755
index 00000000..3897a053
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxCodecSchemaV1_ValidationEncoder.h
+ * @brief Encode the Validation Algorithm and Payload
+ *
+ * Encodes the validation algorithm and payload from the dictionary. Optionally computes
+ * a signature if one is not specified in the dictionary and the encoder has a signer.
+ *
+ */
+
+#ifndef __CCNx_Common__ccnxCodecSchemaV1_ValidationEncoder__
+#define __CCNx_Common__ccnxCodecSchemaV1_ValidationEncoder__
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+
+/**
+ * Appends the Validation Algorithm to the packet encoder
+ *
+ * If the dictionary has a CryptoSuite specified, we will create a ValidationAlgorithm section
+ * and fill it in as per the CryptoSuite and supplied validation algorithm arguments, such as
+ * a KeyId, KeyName, Cert, etc. For most signatures, only the KeyId is mandatory, the other
+ * fields will only be specified if the user put something in the dictionary.
+ *
+ * the caller is responsible for writing the ValidationAlgorithm TL container.
+ *
+ * @param [in] encoder An allocated encoder to append to
+ * @param [in] packetDictionary The dictionary containing the optional headers
+ *
+ * @return non-negative Total bytes appended to encoder
+ * @return -1 An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary);
+
+/**
+ * Appends the Validation Payload to the packet encoder
+ *
+ * This will append the Valdiation Payload from the dictionary, or if it is missing and the
+ * encoder has a signer, will create a signature.
+ *
+ * the caller is responsible for writing the ValidationPayload TL container.
+ *
+ * To create the signature, the caller must have used ccnxCodecTlvEncoder_MarkSignatureStart() and
+ * ccnxCodecTlvEncoder_MarkSignatureEnd() functions to specify the byte locations of the start and
+ * stop of the protected region.
+ *
+ * @param [in] encoder An allocated encoder to append to
+ * @param [in] packetDictionary The dictionary containing the optional headers
+ *
+ * @return non-negative Total bytes appended to encoder
+ * @return -1 An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t ccnxCodecSchemaV1ValidationEncoder_EncodePayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary);
+
+#endif /* defined(__CCNx_Common__ccnxCodecSchemaV1_ValidationEncoder__) */
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore b/libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore
new file mode 100644
index 00000000..ffeaadf8
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore
@@ -0,0 +1,19 @@
+*.gcno
+*.log
+*.trs
+*.o
+test_ccnxCodecSchemaV1_CryptoSuite
+test_ccnxCodecSchemaV1_FixedHeaderDecoder
+test_ccnxCodecSchemaV1_FixedHeaderEncoder
+test_ccnxCodecSchemaV1_LinkCodec
+test_ccnxCodecSchemaV1_MessageDecoder
+test_ccnxCodecSchemaV1_MessageEncoder
+test_ccnxCodecSchemaV1_NameCodec
+test_ccnxCodecSchemaV1_NameSegmentCodec
+test_ccnxCodecSchemaV1_OptionalHeadersDecoder
+test_ccnxCodecSchemaV1_OptionalHeadersEncoder
+test_ccnxCodecSchemaV1_PacketDecoder
+test_ccnxCodecSchemaV1_PacketEncoder
+test_ccnxCodecSchemaV1_TlvDictionary
+test_ccnxCodecSchemaV1_ValidationDecoder
+test_ccnxCodecSchemaV1_ValidationEncoder
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt b/libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt
new file mode 100644
index 00000000..c827a36e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt
@@ -0,0 +1,29 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_ccnxCodecSchemaV1_CryptoSuite
+ test_ccnxCodecSchemaV1_FixedHeaderDecoder
+ test_ccnxCodecSchemaV1_FixedHeaderEncoder
+ test_ccnxCodecSchemaV1_HashCodec
+ test_ccnxCodecSchemaV1_LinkCodec
+ test_ccnxCodecSchemaV1_ManifestDecoder
+ test_ccnxCodecSchemaV1_ManifestEncoder
+ test_ccnxCodecSchemaV1_MessageDecoder
+ test_ccnxCodecSchemaV1_MessageEncoder
+ test_ccnxCodecSchemaV1_NameCodec
+ test_ccnxCodecSchemaV1_NameSegmentCodec
+ test_ccnxCodecSchemaV1_OptionalHeadersDecoder
+ test_ccnxCodecSchemaV1_OptionalHeadersEncoder
+ test_ccnxCodecSchemaV1_PacketDecoder
+ test_ccnxCodecSchemaV1_PacketEncoder
+ test_ccnxCodecSchemaV1_TlvDictionary
+ test_ccnxCodecSchemaV1_ValidationDecoder
+ test_ccnxCodecSchemaV1_ValidationEncoder
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c
new file mode 100644
index 00000000..10bc24d2
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_CryptoSuite.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_CryptoSuite)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_CryptoSuite)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_CryptoSuite)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_ParcToTlv);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_TlvToParc);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_ParcToTlv)
+{
+ struct test_vector {
+ PARCCryptoSuite input;
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite output;
+ bool success;
+ bool sentinel;
+ } vectors[] = {
+ { .input = PARCCryptoSuite_RSA_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, .success = true, .sentinel = false },
+ { .input = PARCCryptoSuite_HMAC_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, .success = true, .sentinel = false },
+ { .input = PARCCryptoSuite_NULL_CRC32C, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, .success = true, .sentinel = false },
+ { .input = PARCCryptoSuite_DSA_SHA256, .output = 0, .success = false, .sentinel = false },
+ { .input = PARCCryptoSuite_RSA_SHA512, .output = 0, .success = false, .sentinel = false },
+ { .input = PARCCryptoSuite_HMAC_SHA512, .output = 0, .success = false, .sentinel = false },
+ { .input = 13579, .output = 0, .success = false, .sentinel = false },
+ { .input = 0, .output = 0, .success = false, .sentinel = true },
+ };
+
+ for (int i = 0; !vectors[i].sentinel; i++) {
+ unsigned output;
+ bool success = ccnxCodecSchemaV1CryptoSuite_ParcToTlv(vectors[i].input, &output);
+ assertTrue(success == vectors[i].success, "Wrong return value, index %d expected %d got %d", i, vectors[i].success, success);
+ if (success) {
+ assertTrue(output == vectors[i].output, "Wrong output, index %d expected %u got %u", i, vectors[i].output, output);
+ }
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_TlvToParc)
+{
+ struct test_vector {
+ PARCCryptoSuite output;
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite input;
+ bool success;
+ bool sentinel;
+ } vectors[] = {
+ { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, .output = PARCCryptoSuite_RSA_SHA256, .success = true, .sentinel = false },
+ { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, .output = PARCCryptoSuite_HMAC_SHA256, .success = true, .sentinel = false },
+ { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, .output = PARCCryptoSuite_NULL_CRC32C, .success = true, .sentinel = false },
+ { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_EcSecp256K1, .output = 0, .success = false, .sentinel = false },
+ { .input = 13579, .output = 0, .success = false, .sentinel = false },
+ { .input = 0, .output = 0, .success = false, .sentinel = true },
+ };
+
+ for (int i = 0; !vectors[i].sentinel; i++) {
+ unsigned output;
+ bool success = ccnxCodecSchemaV1CryptoSuite_TlvToParc(vectors[i].input, &output);
+ assertTrue(success == vectors[i].success, "Wrong return value, index %d expected %d got %d", i, vectors[i].success, success);
+ if (success) {
+ assertTrue(output == vectors[i].output, "Wrong output, index %d expected %u got %u", i, vectors[i].output, output);
+ }
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv)
+{
+ struct test_vector {
+ PARCSigningAlgorithm signAlg;
+ PARCCryptoHashType hashType;
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite output;
+ bool success;
+ bool sentinel;
+ } vectors[] = {
+ { .signAlg = PARCSigningAlgorithm_RSA, .hashType = PARCCryptoHashType_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, .success = true, .sentinel = false },
+ { .signAlg = PARCSigningAlgorithm_HMAC, .hashType = PARCCryptoHashType_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, .success = true, .sentinel = false },
+ { .signAlg = PARCSigningAlgortihm_NULL, .hashType = PARCCryptoHashType_CRC32C, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, .success = true, .sentinel = false },
+ { .signAlg = PARCSigningAlgorithm_RSA, .hashType = 12345, .output = 0, .success = false, .sentinel = false },
+ { .signAlg = PARCSigningAlgorithm_HMAC, .hashType = 12345, .output = 0, .success = false, .sentinel = false },
+ { .signAlg = PARCSigningAlgortihm_NULL, .hashType = 12345, .output = 0, .success = false, .sentinel = false },
+ { .signAlg = 12345, .hashType = 12345, .output = 0, .success = false, .sentinel = false },
+ { .signAlg = 0, .hashType = 0, .output = 0, .success = false, .sentinel = true },
+ };
+
+ for (int i = 0; !vectors[i].sentinel; i++) {
+ unsigned output;
+ bool success = ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv(vectors[i].signAlg, vectors[i].hashType, &output);
+ assertTrue(success == vectors[i].success, "Wrong return value, index %d expected %d got %d", i, vectors[i].success, success);
+ if (success) {
+ assertTrue(output == vectors[i].output, "Wrong output, index %d expected %u got %u", i, vectors[i].output, output);
+ }
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_CryptoSuite);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c
new file mode 100644
index 00000000..7a889b58
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_FixedHeaderDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+typedef struct test_data {
+ uint8_t *packet;
+ PARCBuffer *fixedHeader;
+ CCNxCodecTlvDecoder *decoder;
+ CCNxTlvDictionary *dictionary;
+
+ // truth table
+ uint8_t version;
+ uint8_t packetType;
+ uint16_t packetLength;
+ uint8_t hopLimit;
+ uint8_t returnCode;
+ uint8_t flags;
+ uint8_t headerLength;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->packet = parcMemory_Allocate(8);
+ assertNotNull(data->packet, "parcMemory_Allocate(%d) returned NULL", 8);
+ memcpy(data->packet, &((uint8_t[]) { 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x08 }), 8);
+
+ data->fixedHeader = parcBuffer_Wrap(data->packet, 8, 0, 8);
+ data->version = 0;
+ data->packetType = 1;
+ data->packetLength = 0x0102;
+ data->hopLimit = 3;
+ data->returnCode = 4;
+ data->flags = 5;
+ data->headerLength = 8;
+ data->decoder = ccnxCodecTlvDecoder_Create(data->fixedHeader);
+ data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END);
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+// TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ ccnxTlvDictionary_Release(&data->dictionary);
+ ccnxCodecTlvDecoder_Destroy(&data->decoder);
+ parcBuffer_Release(&data->fixedHeader);
+ parcMemory_Deallocate((void **) &(data->packet));
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_FixedHeaderDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_FixedHeaderDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_FixedHeaderDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_Decode_Underrun);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion_Missing);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthTooShort);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_HeaderLengthTooShort);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthLessHeaderLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/**
+ * Successful decode is tested in all the _GetX functions. We only test
+ * when the buffer is too small here
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_Decode_Underrun)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ // advance the buffer so its too small
+ ccnxCodecTlvDecoder_Advance(data->decoder, 1);
+
+ size_t beforePosition = ccnxCodecTlvDecoder_Position(data->decoder);
+ bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ size_t afterPosition = ccnxCodecTlvDecoder_Position(data->decoder);
+
+ assertFalse(success, "Should have failed with too small a buffer");
+ assertTrue(beforePosition == afterPosition, "Wrong postion, got %zu expected %zu", afterPosition, beforePosition);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int headerLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(data->dictionary);
+ assertTrue(headerLength == data->headerLength, "Wrong headerLength, got %d expected %d", headerLength,
+ data->headerLength);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int packetType = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(data->dictionary);
+ assertTrue(packetType == data->packetType, "Wrong packetType, got %d expected %d", packetType, data->packetType);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int packetLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(data->dictionary);
+ assertTrue(packetLength == data->packetLength, "Wrong payloadLength, got %d expected %d", packetLength,
+ data->packetLength);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(data->dictionary);
+ assertTrue(version == data->version, "Wrong version, got %d expected %d", version, data->version);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int hopLimit = ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit(data->dictionary);
+ assertTrue(hopLimit == data->hopLimit, "Wrong hopLimit, got %d expected %d", hopLimit, data->hopLimit);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int returnCode = ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode(data->dictionary);
+ assertTrue(returnCode == data->returnCode, "Wrong returnCode, got %d expected %d", returnCode, data->returnCode);
+
+ // Check that the InterestReturnCode was set in the fast array, too.
+ uint8_t test =
+ ccnxTlvDictionary_GetInteger(data->dictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode);
+ assertTrue(test == data->returnCode, "Expected the dictionary to have the return code set");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary);
+ int flags = ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags(data->dictionary);
+ assertTrue(flags == data->flags, "Wrong flags, got %d expected %d", flags, data->flags);
+}
+
+
+// ==============================
+// Tests for missing values
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // don't decode the buffer, so we're operating with an empty dictionary
+ int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(data->dictionary);
+ assertTrue(version == -1, "Wrong HeaderLength, got %d expected %d", version, -1);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // don't decode the buffer, so we're operating with an empty dictionary
+ int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(data->dictionary);
+ assertTrue(version == -1, "Wrong PacketType, got %d expected %d", version, -1);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // don't decode the buffer, so we're operating with an empty dictionary
+ int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(data->dictionary);
+ assertTrue(version == -1, "Wrong payloadLength, got %d expected %d", version, -1);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // don't decode the buffer, so we're operating with an empty dictionary
+ int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(data->dictionary);
+ assertTrue(version == -1, "Wrong version, got %d expected %d", version, -1);
+}
+
+
+/**
+ * Packet length must be at least 8 bytes
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthTooShort)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxCodecSchemaV1InterestHeader header = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_Interest,
+ .packetLength = htons(3),
+ .hopLimit = 4,
+ .returnCode = 7,
+ .flags = 8,
+ .headerLength = 9,
+ };
+
+ PARCBuffer *fixedHeader = parcBuffer_Wrap(&header, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(fixedHeader);
+
+ bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(decoder, data->dictionary);
+ assertFalse(success, "Did not fail on packet length too short");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&fixedHeader);
+}
+
+/**
+ * Header length must be at least 8 bytes
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_HeaderLengthTooShort)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxCodecSchemaV1InterestHeader header = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_Interest,
+ .packetLength = htons(12),
+ .hopLimit = 4,
+ .returnCode = 7,
+ .flags = 8,
+ .headerLength = 6,
+ };
+
+ PARCBuffer *fixedHeader = parcBuffer_Wrap(&header, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(fixedHeader);
+
+ bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(decoder, data->dictionary);
+ assertFalse(success, "Did not fail on header length too short");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&fixedHeader);
+}
+
+/**
+ * Packet length must be no less than Header Length
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthLessHeaderLength)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxCodecSchemaV1InterestHeader header = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_Interest,
+ .packetLength = htons(12),
+ .hopLimit = 4,
+ .returnCode = 7,
+ .flags = 8,
+ .headerLength = 18,
+ };
+
+ PARCBuffer *fixedHeader = parcBuffer_Wrap(&header, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(fixedHeader);
+
+ bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(decoder, data->dictionary);
+ assertFalse(success, "Did not fail on packet length less than header length");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&fixedHeader);
+}
+
+// ======================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_FixedHeaderDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c
new file mode 100755
index 00000000..4f479090
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_FixedHeaderEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/codec/test/testrig_Compare.c>
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV0_FixedHeaderEncoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV0_FixedHeaderEncoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV0_FixedHeaderEncoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeContentObject);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterestReturn);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterest)
+{
+ uint16_t packetLength = 0x0102;
+
+ CCNxCodecSchemaV1InterestHeader header = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_Interest,
+ .packetLength = packetLength,
+ .hopLimit = 4,
+ .returnCode = 7, // will be set to 0
+ .flags = 8,
+ .headerLength = 9,
+ };
+
+ CCNxCodecSchemaV1InterestHeader truth = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_Interest,
+ .packetLength = htons(packetLength),
+ .hopLimit = 4,
+ .returnCode = 0,
+ .flags = 8,
+ .headerLength = 9,
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ssize_t length = ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(encoder, (CCNxCodecSchemaV1FixedHeader *) &header);
+ assertTrue(length == 8, "Wrong length, got %zd expected %d", length, 8);
+
+ testCompareEncoderToLinearMemory(encoder, length, (uint8_t *) &truth);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeContentObject)
+{
+ uint16_t packetLength = 0x0102;
+
+ CCNxCodecSchemaV1InterestHeader header = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_ContentObject,
+ .packetLength = packetLength,
+ .hopLimit = 4, // will be set to 0
+ .returnCode = 7, // will be set to 0
+ .flags = 8, // will be set to 0
+ .headerLength = 9,
+ };
+
+ CCNxCodecSchemaV1InterestHeader truth = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_ContentObject,
+ .packetLength = htons(packetLength),
+ .hopLimit = 0,
+ .returnCode = 0,
+ .flags = 0,
+ .headerLength = 9,
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ssize_t length = ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(encoder, (CCNxCodecSchemaV1FixedHeader *) &header);
+ assertTrue(length == 8, "Wrong length, got %zd expected %d", length, 8);
+
+ testCompareEncoderToLinearMemory(encoder, length, (uint8_t *) &truth);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterestReturn)
+{
+ uint16_t packetLength = 0x0102;
+
+ CCNxCodecSchemaV1InterestHeader header = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_InterestReturn,
+ .packetLength = packetLength,
+ .hopLimit = 4,
+ .returnCode = 7,
+ .flags = 8,
+ .headerLength = 9,
+ };
+
+ CCNxCodecSchemaV1InterestHeader truth = {
+ .version = 1,
+ .packetType = CCNxCodecSchemaV1Types_PacketType_InterestReturn,
+ .packetLength = htons(packetLength),
+ .hopLimit = 4,
+ .returnCode = 7,
+ .flags = 8,
+ .headerLength = 9,
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ssize_t length = ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(encoder, (CCNxCodecSchemaV1FixedHeader *) &header);
+ assertTrue(length == 8, "Wrong length, got %zd expected %d", length, 8);
+
+ testCompareEncoderToLinearMemory(encoder, length, (uint8_t *) &truth);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV0_FixedHeaderEncoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c
new file mode 100644
index 00000000..9d03ca2e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_HashCodec.c"
+
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/codec/ccnxCodec_Error.h>
+
+LONGBOW_TEST_RUNNER(ccnxTlvCodec_Hash)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Hash)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Hash)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidHash);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA256);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA512);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_App);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode_InvalidLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue)
+{
+ // -- 32-byte hash
+ uint8_t encoded[] = {
+ 0x00, CCNxCodecSchemaV1Types_HashType_SHA256, 0x00, 0x20,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ };
+
+ PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *payloadBuffer = parcBuffer_Wrap(encoded + 4, sizeof(encoded) - 4, 0, sizeof(encoded) - 4);
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer);
+ PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNotNull(hash, "got non-NULL hash when it should have been an error (null)");
+
+ assertTrue(parcCryptoHash_GetDigestType(hash) == PARCCryptoHashType_SHA256, "Expected to decode the correct hash type.");
+ assertTrue(parcBuffer_Equals(payloadBuffer, parcCryptoHash_GetDigest(hash)), "Expected the digest to match.");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNull(error, "Got null error when it should have been set");
+
+ parcCryptoHash_Release(&hash);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&tlvBuffer);
+ parcBuffer_Release(&payloadBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidHash)
+{
+ // -- 32-byte hash
+ uint8_t encoded[] = {
+ 0x00, 0xFF, 0x00, 0x20,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ };
+
+ PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer);
+ PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(hash, "Should not have decoded an incorrect hash digest");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&tlvBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA256)
+{
+ // -- 32-byte hash
+ uint8_t encoded[] = {
+ 0x00, CCNxCodecSchemaV1Types_HashType_SHA256, 0x00, 0x18,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ };
+
+ PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer);
+ PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(hash, "Should not have decoded a SHA256 hash digest with an incorrect length");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&tlvBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA512)
+{
+ // -- 32-byte hash
+ uint8_t encoded[] = {
+ 0x00, CCNxCodecSchemaV1Types_HashType_SHA512, 0x00, 0x18,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ };
+
+ PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer);
+ PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(hash, "Should not have decoded a SHA512 hash digest with an incorrect length");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&tlvBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_App)
+{
+ // -- 32-byte hash
+ uint8_t encoded[] = {
+ 0x00, CCNxCodecSchemaV1Types_HashType_App, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00,0x00,0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer);
+ PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNotNull(hash, "Should have decoded an application hash digest with an arbitrary length");
+
+ parcCryptoHash_Release(&hash);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&tlvBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode)
+{
+ uint8_t encoded[] = {
+ 0x00, CCNxCodecSchemaV1Types_HashType_SHA256, 0x00, 0x20,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,
+ };
+
+ PARCBuffer *trueEncoding = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ // Create the hash
+ PARCBuffer *payloadBuffer = parcBuffer_Allocate(0x20);
+ PARCCryptoHash *expectedHash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, payloadBuffer);
+
+ // Encode it
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1HashCodec_Encode(encoder, expectedHash);
+ assertFalse(length < 0, "Got error on encode: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zd got %zd", sizeof(encoded), length);
+
+ // Check for equality
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *testEncoding = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(trueEncoding, testEncoding), "The hash was encoded incorrectly.")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueEncoding, 3);
+ printf("Got\n");
+ parcBuffer_Display(testEncoding, 3);
+ }
+
+ parcBuffer_Release(&testEncoding);
+ parcBuffer_Release(&trueEncoding);
+
+ parcCryptoHash_Release(&expectedHash);
+ parcBuffer_Release(&payloadBuffer);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode_InvalidLength)
+{
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Hash);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c
new file mode 100755
index 00000000..599e3a5a
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_LinkCodec.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/codec/ccnxCodec_Error.h>
+
+LONGBOW_TEST_RUNNER(ccnxTlvCodec_Name)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Name)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Name)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NameOnly);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_AllFields);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NoName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_ExtraField);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupHash);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_FieldOverrun);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_Underrun);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1LinkCodec_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NameOnly)
+{
+ CCNxName *truth = ccnxName_CreateFromCString("lci:/3=rope");
+
+ uint8_t encoded[] = {
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNotNull(link, "got null link: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ const CCNxName *test = ccnxLink_GetName(link);
+ assertTrue(ccnxName_Equals(truth, test), "Wrong name")
+ {
+ printf("Expected\n");
+ ccnxName_Display(truth, 3);
+ printf("Got\n");
+ ccnxName_Display(test, 3);
+ }
+
+ PARCBuffer *testKeyid = ccnxLink_GetKeyID(link);
+ assertNull(testKeyid, "Got a keyid without the wire encoding for it");
+
+ PARCBuffer *testHash = ccnxLink_GetContentObjectHash(link);
+ assertNull(testHash, "got a hash without the wire encoding for it");
+
+ ccnxLink_Release(&link);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+ ccnxName_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_AllFields)
+{
+ CCNxName *truth = ccnxName_CreateFromCString("lci:/3=rope");
+
+ uint8_t encoded[] = {
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNotNull(link, "got null link: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ const CCNxName *test = ccnxLink_GetName(link);
+ assertTrue(ccnxName_Equals(truth, test), "Wrong name")
+ {
+ printf("Expected\n");
+ ccnxName_Display(truth, 3);
+ printf("Got\n");
+ ccnxName_Display(test, 3);
+ }
+
+ PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 16, 24);
+ PARCBuffer *testKeyid = ccnxLink_GetKeyID(link);
+ assertTrue(parcBuffer_Equals(keyid, testKeyid), "Wrong keyid")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(keyid, 3);
+ printf("Got\n");
+ parcBuffer_Display(testKeyid, 3);
+ }
+
+ PARCBuffer *hash = parcBuffer_Wrap(encoded, sizeof(encoded), 28, 44);
+ PARCBuffer *testHash = ccnxLink_GetContentObjectHash(link);
+ assertTrue(parcBuffer_Equals(hash, testHash), "Wrong hash")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(hash, 3);
+ printf("Got\n");
+ parcBuffer_Display(testHash, 3);
+ }
+
+ parcBuffer_Release(&hash);
+ parcBuffer_Release(&keyid);
+
+ ccnxLink_Release(&link);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+ ccnxName_Release(&truth);
+}
+
+/*
+ * wire format missing name
+ */
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NoName)
+{
+ uint8_t encoded[] = {
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+/*
+ * Wire format has an extra TLV in it that's not part of the spec
+ */
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_ExtraField)
+{
+ uint8_t encoded[] = {
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ // -- extra
+ 0x00, 0xFF, 0x00, 4,
+ 0xc0, 0xc1, 0xc2, 0xc3,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupName)
+{
+ uint8_t encoded[] = {
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupKeyId)
+{
+ uint8_t encoded[] = {
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupHash)
+{
+ uint8_t encoded[] = {
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_FieldOverrun)
+{
+ // name length is beyond end of fragment
+ uint8_t encoded[] = {
+ 0x00, 0x00, 0x00, 30,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_Underrun)
+{
+ // buffer is too short to even parse the T and L
+ uint8_t encoded[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ // the "2" makes it too short to parse
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, 2);
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded));
+ assertNull(link, "got non-null link when it should have been an error (null)");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Got null error when it should have been set");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+// ============
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1LinkCodec_Encode)
+{
+ uint8_t encoded[] = {
+ // -- name
+ 0x00, 0x00, 0x00, 8,
+ 0x00, 0x03, 0x00, 4,
+ 'r', 'o', 'p', 'e',
+ // -- keyid
+ 0x00, 0x01, 0x00, 8,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ // -- hash
+ 0x00, 0x02, 0x00, 16,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ };
+
+ CCNxName *trueName = ccnxName_CreateFromCString("lci:/3=rope");
+ PARCBuffer *trueKeyId = parcBuffer_Wrap(encoded, sizeof(encoded), 16, 24);
+ PARCBuffer *trueHash = parcBuffer_Wrap(encoded, sizeof(encoded), 28, 44);
+ PARCBuffer *trueEncoding = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxLink *link = ccnxLink_Create(trueName, trueKeyId, trueHash);
+
+ // now encode it and compare the the trueEncoding
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ssize_t length = ccnxCodecSchemaV1LinkCodec_Encode(encoder, link);
+ assertFalse(length < 0, "Got error on encode: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zd got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *testEncoding = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(trueEncoding, testEncoding), "Wrong hash")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueEncoding, 3);
+ printf("Got\n");
+ parcBuffer_Display(testEncoding, 3);
+ }
+
+ parcBuffer_Release(&testEncoding);
+ parcBuffer_Release(&trueEncoding);
+ parcBuffer_Release(&trueHash);
+ parcBuffer_Release(&trueKeyId);
+ ccnxName_Release(&trueName);
+
+ ccnxLink_Release(&link);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Name);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c
new file mode 100755
index 00000000..3c1609ab
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_ManifestDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "testrig_encoder.c"
+
+#include <ccnx/common/ccnx_Manifest.h>
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ManifestDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ManifestDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ManifestDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_Decode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroup);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroupMetadata);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_Decode)
+{
+ uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24,
+ 0x00, 0x02, 0x00, 0x20,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46 };
+ PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat);
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest();
+
+ bool result = ccnxCodecSchemaV1ManifestDecoder_Decode(decoder, dict);
+ assertTrue(result, "Expected the manifest to be decoded correctly");
+
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&wireFormat);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeType)
+{
+ uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24,
+ 0x00, 0x02, 0x00, 0x20,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46 };
+ PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat);
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest();
+
+ uint16_t type = ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ bool result = _decodeType(decoder, dict, type, length);
+ assertTrue(result, "Expected the manifest type to be correctly decoded at the top level");
+
+ ccnxManifest_Release(&dict);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&wireFormat);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroup)
+{
+ uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24,
+ 0x00, 0x02, 0x00, 0x20,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x46, 0x46 };
+ PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat);
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest();
+
+ ccnxCodecTlvDecoder_GetType(decoder); // swallow type
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ bool result = _decodeHashGroup(decoder, dict, group, length);
+ assertTrue(result, "Expected hash group to be decoded correctly.");
+
+ PARCBuffer *expectedPointer = parcBuffer_AllocateCString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+ CCNxManifestHashGroupPointer *pointer = ccnxManifestHashGroup_GetPointerAtIndex(group, 0);
+ const PARCBuffer *actualPointer = ccnxManifestHashGroupPointer_GetDigest(pointer);
+ assertTrue(parcBuffer_Equals(expectedPointer, actualPointer), "Expected decoded pointer to equal %s, got %s", parcBuffer_ToHexString(expectedPointer), parcBuffer_ToHexString(actualPointer));
+
+ parcBuffer_Release(&expectedPointer);
+
+ ccnxManifestHashGroup_Release(&group);
+ ccnxManifest_Release(&dict);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&wireFormat);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroupMetadata)
+{
+ // Re-build the expected metadata from the manifest
+ CCNxName *groupLocator = ccnxName_CreateFromCString("ccnx:/locator");
+ PARCBuffer *digest = parcBuffer_Allocate(16);
+ for (size_t i = 0; i < parcBuffer_Limit(digest); i++) {
+ parcBuffer_PutUint8(digest, 0);
+ }
+ parcBuffer_Flip(digest);
+ size_t entrySize = 1;
+ size_t dataSize = 2;
+ size_t blockSize = 3;
+ size_t treeHeight = 4;
+
+ // Compute the expected size of this metadata group.
+ size_t metadataSize = 4 * (4 + 8) + 4 + parcBuffer_Limit(digest) + 4 + strlen("ccnx:/locator");
+
+ // See test_ccnxCodecSchemaV1_ManifestEncoder.c for the packet construction details.
+ uint8_t rawMetadata[89] = { 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata,
+ 0x00, metadataSize,
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator,
+ 0x00, strlen("ccnx:/locator"),
+ 'c', 'c',
+ 'n', 'x',
+ ':', '/',
+ 'l', 'o',
+ 'c', 'a',
+ 't', 'o',
+ 'r',
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize,
+ 0x00, 0x08,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, dataSize,
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize,
+ 0x00, 0x08,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, blockSize,
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize,
+ 0x00, 0x08,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, entrySize,
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight,
+ 0x00, 0x08,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, treeHeight,
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256,
+ 0x00, parcBuffer_Remaining(digest),
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00 };
+ PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawMetadata, sizeof(rawMetadata)));
+
+ // Create the encoder and swallow the top level container
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat);
+ ccnxCodecTlvDecoder_GetType(decoder); // swallow type
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ // Decode the metadata
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ bool result = _decodeHashGroupMetadata(decoder, group, length);
+ assertTrue(result, "Expected hash group metadata to be decoded correctly.");
+
+ const CCNxName *actualLocator = ccnxManifestHashGroup_GetLocator(group);
+ size_t actualEntrySize = ccnxManifestHashGroup_GetEntrySize(group);
+ size_t actualDataSize = ccnxManifestHashGroup_GetDataSize(group);
+ size_t actualBlockSize = ccnxManifestHashGroup_GetBlockSize(group);
+ size_t actualTreeHeight = ccnxManifestHashGroup_GetTreeHeight(group);
+ const PARCBuffer *actualDigest = ccnxManifestHashGroup_GetOverallDataDigest(group);
+
+ assertTrue(ccnxName_Equals(groupLocator, actualLocator), "Expected decoded locator to equal %s, got %s", ccnxName_ToString(groupLocator), ccnxName_ToString(actualLocator));
+ assertTrue(entrySize == actualEntrySize, "Expected %zu entry size, got %zu", entrySize, actualEntrySize);
+ assertTrue(dataSize == actualDataSize, "Expected %zu data size, got %zu", dataSize, actualDataSize);
+ assertTrue(blockSize == actualBlockSize, "Expected %zu block size, got %zu", blockSize, actualBlockSize);
+ assertTrue(treeHeight == actualTreeHeight, "Expected %zu tree height, got %zu", treeHeight, actualTreeHeight);
+ assertTrue(parcBuffer_Equals(digest, actualDigest), "Expected %s digest, got %s", parcBuffer_ToHexString(digest), parcBuffer_ToHexString(actualDigest));
+
+ parcBuffer_Release(&digest);
+ ccnxName_Release(&groupLocator);
+
+ ccnxManifestHashGroup_Release(&group);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&wireFormat);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ManifestDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c
new file mode 100755
index 00000000..a0e36abf
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_ManifestEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "testrig_encoder.c"
+
+#include <ccnx/common/ccnx_Manifest.h>
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ManifestEncoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ManifestEncoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ManifestEncoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeEmpty);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup_WithMetadata);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_AddPointer);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeEmpty)
+{
+ CCNxName *locator = ccnxName_CreateFromCString("lci:/name");
+ CCNxManifest *manifest = ccnxManifest_Create(locator);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest);
+
+ assertTrue(result == 0, "Expected an empty Manifest to be encoded to size 0, got %zu", result);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxManifest_Release(&manifest);
+ ccnxName_Release(&locator);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_AddPointer)
+{
+ CCNxName *locator = ccnxName_CreateFromCString("ccnx:/name");
+ CCNxManifest *manifest = ccnxManifest_Create(locator);
+
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ PARCBuffer *pointer = parcBuffer_Flip(parcBuffer_ParseHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, pointer);
+
+ ccnxManifest_AddHashGroup(manifest, group);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest);
+ size_t expected = 4 + 4 + parcBuffer_Remaining(pointer); // hash group TL, pointer TL, pointer V
+
+ assertTrue(result == expected, "Expected an empty Manifest to be encoded to size %zu, got %zu", expected, result);
+
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder);
+ const struct iovec *vector = ccnxCodecNetworkBufferIoVec_GetArray(iovec);
+
+ assertTrue(vector->iov_len == expected, "Expected the IO vector to contain the encoded manifest");
+ assertTrue(memcmp(vector->iov_base + 8, parcBuffer_Overlay(pointer, parcBuffer_Remaining(pointer)), vector->iov_len - 8) == 0, "Expected the same pointer to be encoded");
+
+ uint16_t expectedType = CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer;
+ uint8_t *base = (uint8_t *) vector->iov_base;
+ uint16_t actualType = (base[4] << 8) | base[5];
+ assertTrue(expectedType == actualType, "Expected the type to be written correctly as CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer");
+
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+
+ // Cleanup
+ parcBuffer_Release(&pointer);
+ ccnxManifestHashGroup_Release(&group);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxManifest_Release(&manifest);
+ ccnxName_Release(&locator);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup)
+{
+ CCNxName *locator = ccnxName_CreateFromCString("ccnx:/name");
+ CCNxManifest *manifest = ccnxManifest_Create(locator);
+
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ PARCBuffer *pointer = parcBuffer_Flip(parcBuffer_ParseHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, pointer);
+
+ ccnxManifest_AddHashGroup(manifest, group);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest);
+ size_t expected = 4 + 4 + parcBuffer_Remaining(pointer); // hash group TL, pointer TL, pointer V
+
+ assertTrue(result == expected, "Expected an empty Manifest to be encoded to size %zu, got %zu", expected, result);
+
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder);
+ const struct iovec *vector = ccnxCodecNetworkBufferIoVec_GetArray(iovec);
+
+ uint8_t expectedVector[24] = { 0x00, 0x07, 0x00, 0x14,
+ 0x00, 0x02, 0x00, 0x10,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF };
+ assertTrue(vector->iov_len == expected, "Expected the IO vector to contain the encoded manifest");
+ assertTrue(memcmp(vector->iov_base, expectedVector, vector->iov_len) == 0, "Expected the same pointer to be encoded");
+
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+
+ // Cleanup
+ parcBuffer_Release(&pointer);
+ ccnxManifestHashGroup_Release(&group);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxManifest_Release(&manifest);
+ ccnxName_Release(&locator);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup_WithMetadata)
+{
+ CCNxName *locator = ccnxName_CreateFromCString("ccnx:/name");
+ CCNxManifest *manifest = ccnxManifest_Create(locator);
+
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ PARCBuffer *pointer = parcBuffer_Flip(parcBuffer_ParseHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, pointer);
+
+ // Set the metadata now
+ CCNxName *groupLocator = ccnxName_CreateFromCString("ccnx:/locator");
+ ccnxManifestHashGroup_SetLocator(group, groupLocator);
+
+ PARCBuffer *digest = parcBuffer_Allocate(16);
+ for (size_t i = 0; i < parcBuffer_Limit(digest); i++) {
+ parcBuffer_PutUint8(digest, 0);
+ }
+ parcBuffer_Flip(digest);
+ ccnxManifestHashGroup_SetOverallDataDigest(group, digest);
+
+ size_t entrySize = 1;
+ ccnxManifestHashGroup_SetEntrySize(group, entrySize);
+
+ size_t dataSize = 2;
+ ccnxManifestHashGroup_SetDataSize(group, dataSize);
+
+ size_t blockSize = 3;
+ ccnxManifestHashGroup_SetBlockSize(group, blockSize);
+
+ size_t treeHeight = 4;
+ ccnxManifestHashGroup_SetTreeHeight(group, treeHeight);
+
+ // Add the hash group to the manifest
+ ccnxManifest_AddHashGroup(manifest, group);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest);
+
+ // Compute the expected size with all of the metadata.
+ // This packet was crafted by hand.
+ size_t expected = 4; // hash group TL
+ expected += 4 + parcBuffer_Remaining(pointer); // pointer TL, pointer V
+ expected += 4; // metadata TL
+ expected += 4 * (4 + 8); // 64-bit integer property TLs, Vs
+ expected += 4 + parcBuffer_Remaining(digest); // digest T and V
+ expected += 4 + strlen("ccnx:/locator"); // name TL, segment TL, and segment V
+
+ // Compute only the size of the metadata
+ size_t metadataSize = expected;
+ metadataSize -= 4; // top-level TL container
+ metadataSize -= (4 + parcBuffer_Remaining(pointer)); // pointer TLV
+ metadataSize -= 4; // metadata TL container
+
+ assertTrue(result == expected, "Expected an empty Manifest to be encoded to size %zu, got %zu", expected, result);
+
+ // Now do the encoding
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder);
+ const struct iovec *vector = ccnxCodecNetworkBufferIoVec_GetArray(iovec);
+
+ uint8_t expectedVector[129] = { 0x00, 0x07,
+ 0x00, expected - 4,
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata,
+ 0x00, metadataSize,
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator,
+ 0x00, strlen("ccnx:/locator"),
+ 'c', 'c',
+ 'n', 'x',
+ ':', '/',
+ 'l', 'o',
+ 'c', 'a',
+ 't', 'o',
+ 'r',
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize,
+ 0x00, 0x08,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, dataSize,
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize,
+ 0x00, 0x08,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, blockSize,
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize,
+ 0x00, 0x08,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, entrySize,
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight,
+ 0x00, 0x08,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, treeHeight,
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256,
+ 0x00, parcBuffer_Remaining(digest),
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer,
+ 0x00, parcBuffer_Remaining(pointer),
+ 0xFF, 0xFF,
+ 0xFF, 0xFF,
+ 0xFF, 0xFF,
+ 0xFF, 0xFF,
+ 0xFF, 0xFF,
+ 0xFF, 0xFF,
+ 0xFF, 0xFF,
+ 0xFF, 0xFF };
+ assertTrue(vector->iov_len == expected, "Expected the IO vector to contain the encoded manifest");
+ assertTrue(memcmp(vector->iov_base, expectedVector, vector->iov_len) == 0, "Expected the same HashGroup to be encoded");
+
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+
+ // Cleanup
+ parcBuffer_Release(&pointer);
+ parcBuffer_Release(&digest);
+ ccnxManifestHashGroup_Release(&group);
+ ccnxName_Release(&groupLocator);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxManifest_Release(&manifest);
+ ccnxName_Release(&locator);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ManifestEncoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c
new file mode 100644
index 00000000..ab339fc1
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_MessageDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+
+#include "testrig_packetwrapper.c"
+
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_MessageDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(ContentObject);
+ LONGBOW_RUN_TEST_FIXTURE(Interest);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_MessageDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_MessageDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// =========================================================================
+// Utility functions to get a field in the format we expect for the testrig.
+// We cannot use the facades because those try to assert a type on the dictionary which
+// is not part of the MessageDecoder.
+
+static CCNxName *
+_getName(CCNxTlvDictionary *contentObjectDictionary)
+{
+ return ccnxTlvDictionary_GetName(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+}
+
+static PARCBuffer *
+_getPayload(const CCNxTlvDictionary *contentObjectDictionary)
+{
+ return ccnxTlvDictionary_GetBuffer(contentObjectDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+}
+
+static int64_t
+_getPayloadType(CCNxTlvDictionary *contentObjectDictionary)
+{
+ return (int64_t) ccnxTlvDictionary_GetInteger(contentObjectDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE);
+}
+
+static int64_t
+_getExpiryTime(CCNxTlvDictionary *contentObjectDictionary)
+{
+ return (int64_t) ccnxTlvDictionary_GetInteger(contentObjectDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME);
+}
+
+static int64_t
+_getEndChunkNumber(CCNxTlvDictionary *contentObjectDictionary)
+{
+ return (int64_t) ccnxTlvDictionary_GetInteger(contentObjectDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT);
+}
+
+static PARCCryptoHash *
+_getKeyIdRestriction(CCNxTlvDictionary *messageDictionary)
+{
+ return (PARCCryptoHash *) ccnxTlvDictionary_GetObject(messageDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION);
+}
+
+static PARCCryptoHash *
+_getHashRestriction(CCNxTlvDictionary *messageDictionary)
+{
+ return (PARCCryptoHash *) ccnxTlvDictionary_GetObject(messageDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(ContentObject)
+{
+ LONGBOW_RUN_TEST_CASE(ContentObject, Name);
+ LONGBOW_RUN_TEST_CASE(ContentObject, Payload);
+ LONGBOW_RUN_TEST_CASE(ContentObject, PayloadType);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ExpiryTime);
+ LONGBOW_RUN_TEST_CASE(ContentObject, EndChunkNumber);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ContentObject)
+{
+ longBowTestCase_SetClipBoardData(testCase,
+ commonSetup(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ v1_content_nameA_keyid1_rsasha256_truthTableEntries,
+ V1_MANIFEST_OBJ_CONTENTOBJECT));
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject)
+{
+ commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(ContentObject, Name)
+{
+// TestData *data = longBowTestCase_GetClipBoardData(testCase);
+// testNameGetter(data, V1_MANIFEST_OBJ_NAME, ccnxCodecSchemaV1MessageDecoder_Decode, _getName);
+}
+
+LONGBOW_TEST_CASE(ContentObject, Payload)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testBufferGetter(data, V1_MANIFEST_OBJ_PAYLOAD, ccnxCodecSchemaV1MessageDecoder_Decode, _getPayload);
+}
+
+LONGBOW_TEST_CASE(ContentObject, PayloadType)
+{
+ // The payload type is translated from the wire format value to the CCNxPayloadType value,
+ // so this test cannot use the automated framework as the value in the dictionary will not
+ // be the same as the value in the wire format
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ bool decodeSuccess = ccnxCodecSchemaV1MessageDecoder_Decode(data->decoder, data->dictionary);
+ assertTrue(decodeSuccess, "failure on ccnxCodecSchemaV1MessageDecoder_Decode");
+
+ CCNxPayloadType testPayloadType = (CCNxPayloadType) _getPayloadType(data->dictionary);
+
+ // look up the true name buffer from the truth table
+ TlvExtent extent = getTruthTableExtent(data->truthTable, V1_MANIFEST_OBJ_PAYLOADTYPE);
+
+ PARCBuffer
+ *truthbuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length);
+ uint64_t truthvalue = -2;
+ ccnxCodecTlvUtilities_GetVarInt(truthbuffer, parcBuffer_Remaining(truthbuffer), &truthvalue);
+
+ CCNxPayloadType truthPayloadType = -1;
+ bool success =
+ _translateWirePayloadTypeToCCNxPayloadType((CCNxCodecSchemaV1Types_PayloadType) truthvalue, &truthPayloadType);
+ assertTrue(success, "failure in _translateWirePayloadTypeToCCNxPayloadType for wireFormatValue %"
+ PRId64, truthvalue);
+
+ parcBuffer_Release(&truthbuffer);
+
+ assertTrue(truthPayloadType == testPayloadType, "Wrong value, got %d expected %d", testPayloadType,
+ truthPayloadType);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ExpiryTime)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testInt64Getter(data, V1_MANIFEST_OBJ_EXPIRY_TIME, ccnxCodecSchemaV1MessageDecoder_Decode, _getExpiryTime);
+}
+
+LONGBOW_TEST_CASE(ContentObject, EndChunkNumber)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testInt64Getter(data, V1_MANIFEST_OBJ_ENDSEGMENT, ccnxCodecSchemaV1MessageDecoder_Decode, _getEndChunkNumber);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Interest)
+{
+ LONGBOW_RUN_TEST_CASE(Interest, Name);
+ LONGBOW_RUN_TEST_CASE(Interest, Payload);
+ LONGBOW_RUN_TEST_CASE(Interest, KeyIdRestriction);
+ LONGBOW_RUN_TEST_CASE(Interest, HashRestriction);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Interest)
+{
+ longBowTestCase_SetClipBoardData(testCase,
+ commonSetup(v1_interest_all_fields,
+ sizeof(v1_interest_all_fields),
+ TRUTHTABLENAME(v1_interest_all_fields),
+ V1_MANIFEST_INT_INTEREST));
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Interest)
+{
+ commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Interest, Name)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testNameGetter(data, V1_MANIFEST_INT_NAME, ccnxCodecSchemaV1MessageDecoder_Decode, _getName);
+}
+
+LONGBOW_TEST_CASE(Interest, Payload)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testBufferGetter(data, V1_MANIFEST_INT_PAYLOAD, ccnxCodecSchemaV1MessageDecoder_Decode, _getPayload);
+}
+
+LONGBOW_TEST_CASE(Interest, KeyIdRestriction)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testHashGetter(data, V1_MANIFEST_INT_KEYID, ccnxCodecSchemaV1MessageDecoder_Decode, _getKeyIdRestriction);
+}
+
+LONGBOW_TEST_CASE(Interest, HashRestriction)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ testHashGetter(data, V1_MANIFEST_INT_OBJHASH, ccnxCodecSchemaV1MessageDecoder_Decode, _getHashRestriction);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _translateWirePayloadTypeToCCNxPayloadType);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _translateWirePayloadTypeToCCNxPayloadType)
+{
+ uint32_t sentinel = 0xFFFF;
+
+ struct {
+ CCNxCodecSchemaV1Types_PayloadType wire;
+ CCNxPayloadType payloadType;
+ bool success;
+ } vectors[] = {
+ { .wire = CCNxCodecSchemaV1Types_PayloadType_Data, .payloadType = CCNxPayloadType_DATA, .success = true },
+ { .wire = CCNxCodecSchemaV1Types_PayloadType_Key, .payloadType = CCNxPayloadType_KEY, .success = true },
+ { .wire = CCNxCodecSchemaV1Types_PayloadType_Link, .payloadType = CCNxPayloadType_LINK, .success = true },
+ { .wire = -2, .payloadType = -2, .success = false },
+ { .wire = sentinel, .payloadType = sentinel }
+ };
+
+ for (int i = 0; vectors[i].wire != sentinel; i++) {
+ CCNxPayloadType payloadType = -1;
+ bool success = _translateWirePayloadTypeToCCNxPayloadType(vectors[i].wire, &payloadType);
+ assertTrue(success == vectors[i].success, "Incorrect return index %d, expected %d got %d", i,
+ vectors[i].success, success);
+
+ if (success) {
+ assertTrue(payloadType == vectors[i].payloadType, "Wrong payloadType index %d, expected %d got %d", i,
+ vectors[i].payloadType, payloadType);
+ }
+ }
+}
+
+// =========================================================================
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_MessageDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c
new file mode 100644
index 00000000..49452626
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c
@@ -0,0 +1,644 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_MessageEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h>
+
+#include "testrig_encoder.c"
+
+#include <ccnx/common/ccnx_ContentObject.h>
+#include <ccnx/common/ccnx_Interest.h>
+
+#include <ccnx/common/internal/ccnx_InterestDefault.h>
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_MessageEncoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(UnknownType);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_MessageEncoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_MessageEncoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(ContentObject, Interest);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObjectNameless);
+ LONGBOW_RUN_TEST_CASE(InterestReturn, InterestReturn);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(ContentObject, Interest)
+{
+ // create an Interest that replicates v1_interest_all_fields
+ TlvExtent keyidExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_KEYID);
+ TlvExtent hashExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_OBJHASH);
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_PAYLOAD);
+ TlvExtent interestExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_INTEREST);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/3=cool");
+ uint32_t lifetime = CCNxInterestDefault_LifetimeMilliseconds;
+ uint32_t hoplimit = CCNxInterestDefault_HopLimit;
+
+ printf("%d %d\n", keyidExtent.offset + 4, keyidExtent.offset + keyidExtent.length - 4);
+ PARCBuffer *keyid = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), keyidExtent.offset + 4, keyidExtent.offset + keyidExtent.length);
+ PARCBuffer *hash = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), hashExtent.offset + 4, hashExtent.offset + hashExtent.length);
+ PARCBuffer *payload = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ CCNxTlvDictionary *interest =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name, lifetime, keyid, hash, hoplimit);
+
+ ccnxInterest_SetPayloadAndId(interest, payload);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecSchemaV1MessageEncoder_Encode(encoder, interest);
+
+ PARCBuffer *truth = parcBuffer_Wrap(v1_interest_all_fields,
+ sizeof(v1_interest_all_fields),
+ interestExtent.offset,
+ interestExtent.offset + interestExtent.length);
+
+ testCompareEncoderToBuffer(encoder, truth);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&payload);
+ parcBuffer_Release(&hash);
+ parcBuffer_Release(&keyid);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&interest);
+}
+
+LONGBOW_TEST_CASE(InterestReturn, InterestReturn)
+{
+ // create an Interest that replicates v1_interest_all_fields
+ TlvExtent keyidExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_KEYID);
+ TlvExtent hashExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_OBJHASH);
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_PAYLOAD);
+ TlvExtent interestExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_INTEREST);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/3=cool");
+ uint32_t lifetime = CCNxInterestDefault_LifetimeMilliseconds;
+ uint32_t hoplimit = CCNxInterestDefault_HopLimit;
+
+ PARCBuffer *keyid = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), keyidExtent.offset + 4, keyidExtent.offset + keyidExtent.length);
+ PARCBuffer *hash = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), hashExtent.offset + 4, hashExtent.offset + hashExtent.length);
+ PARCBuffer *payload = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ CCNxTlvDictionary *interest =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name, lifetime, keyid, hash, hoplimit);
+ parcBuffer_Release(&hash);
+ parcBuffer_Release(&keyid);
+ ccnxName_Release(&name);
+
+ ccnxInterest_SetPayloadAndId(interest, payload);
+ parcBuffer_Release(&payload);
+
+ CCNxInterestReturn *interestReturn =
+ ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_HopLimitExceeded);
+ ccnxTlvDictionary_Release(&interest);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecSchemaV1MessageEncoder_Encode(encoder, interestReturn);
+
+ size_t packetSize = sizeof(v1_interest_all_fields);
+ uint8_t *testPacket = (uint8_t *) parcSafeMemory_Allocate(packetSize);
+ memcpy(testPacket, v1_interest_all_fields, packetSize);
+ testPacket[1] = 0x02; //InterestReturn
+ testPacket[5] = CCNxInterestReturn_ReturnCode_HopLimitExceeded;
+
+ PARCBuffer *truth = parcBuffer_Wrap(testPacket, packetSize,
+ interestExtent.offset,
+ interestExtent.offset + interestExtent.length);
+
+ testCompareEncoderToBuffer(encoder, truth);
+
+ parcSafeMemory_Deallocate((void **) &testPacket);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ ccnxInterestReturn_Release(&interestReturn);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObjectNameless)
+{
+ // create a Content Object that replicates v1_content_nameA_keyid1_rsasha256
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameless_nosig), V1_MANIFEST_OBJ_PAYLOAD);
+ TlvExtent contentObjectExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameless_nosig), V1_MANIFEST_OBJ_CONTENTOBJECT);
+
+ PARCBuffer *payload = parcBuffer_Wrap(v1_content_nameless_nosig, sizeof(v1_content_nameless_nosig), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ CCNxTlvDictionary *contentobject =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ NULL, CCNxPayloadType_KEY, payload);
+
+ ccnxContentObject_SetExpiryTime(contentobject, 0x01434B198400ULL);
+ ccnxContentObject_SetFinalChunkNumber(contentobject, 0x06050403);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecSchemaV1MessageEncoder_Encode(encoder, contentobject);
+
+ PARCBuffer *truth = parcBuffer_Wrap(v1_content_nameless_nosig, sizeof(v1_content_nameless_nosig), contentObjectExtent.offset, contentObjectExtent.offset + contentObjectExtent.length);
+
+ testCompareEncoderToBuffer(encoder, truth);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&payload);
+ ccnxTlvDictionary_Release(&contentobject);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject)
+{
+ // create a Content Object that replicates v1_content_nameA_keyid1_rsasha256
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_PAYLOAD);
+ TlvExtent contentObjectExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_CONTENTOBJECT);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/3=hello/0xf000=ouch");
+
+ PARCBuffer *payload = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ CCNxTlvDictionary *contentobject =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name, CCNxPayloadType_KEY, payload);
+
+ ccnxContentObject_SetExpiryTime(contentobject, 0x01434B198400ULL);
+ ccnxContentObject_SetFinalChunkNumber(contentobject, 0x06050403);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecSchemaV1MessageEncoder_Encode(encoder, contentobject);
+
+ PARCBuffer *truth = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), contentObjectExtent.offset, contentObjectExtent.offset + contentObjectExtent.length);
+
+ testCompareEncoderToBuffer(encoder, truth);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&contentobject);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Interest)
+{
+ LONGBOW_RUN_TEST_CASE(Interest, ccnxCodecSchemaV1MessageEncoder_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Interest)
+{
+ longBowTestCase_SetClipBoardData(testCase,
+ commonSetup(v1_interest_all_fields,
+ sizeof(v1_interest_all_fields),
+ TRUTHTABLENAME(v1_interest_all_fields),
+ V1_MANIFEST_INT_INTEREST));
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Interest)
+{
+ testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Interest, ccnxCodecSchemaV1MessageEncoder_Encode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1MessageEncoder_Encode(data->encoder, data->dictionary);
+
+ testCompareEncoderToBuffer(data->encoder, data->memoryRegion);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(InterestReturn)
+{
+ LONGBOW_RUN_TEST_CASE(InterestReturn, ccnxCodecSchemaV1MessageEncoder_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(InterestReturn)
+{
+ size_t packetSize = sizeof(v1_interest_all_fields);
+ uint8_t *testPacket = (uint8_t *) parcSafeMemory_Allocate(packetSize);
+ memcpy(testPacket, v1_interest_all_fields, packetSize);
+ testPacket[1] = 0x02; //InterestReturn
+ testPacket[5] = CCNxInterestReturn_ReturnCode_HopLimitExceeded;
+
+ longBowTestCase_SetClipBoardData(testCase,
+ commonSetup(v1_interest_all_fields,
+ sizeof(v1_interest_all_fields),
+ TRUTHTABLENAME(v1_interest_all_fields),
+ V1_MANIFEST_INT_INTEREST));
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(InterestReturn)
+{
+ testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(InterestReturn, ccnxCodecSchemaV1MessageEncoder_Encode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1MessageEncoder_Encode(data->encoder, data->dictionary);
+
+ testCompareEncoderToBuffer(data->encoder, data->memoryRegion);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _encodeName);
+ LONGBOW_RUN_TEST_CASE(Local, _encodePayload);
+ LONGBOW_RUN_TEST_CASE(Local, _encodePayloadType);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeExpiryTime);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeEndChunkNumber);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeKeyIdRestriction);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeContentObjectHashRestriction);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+#include <parc/algol/parc_Varint.h>
+
+LONGBOW_TEST_CASE(Local, _encodeName)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/0xf001=foot/0xf002=toe/0xf003=nail");
+ uint8_t encoded[] = {
+ 0x00, 0x00, 0x00, 23,
+ 0xF0, 0x01, 0x00, 4,
+ 'f', 'o', 'o', 't',
+ 0xF0, 0x02, 0x00, 3,
+ 't', 'o', 'e',
+ 0xF0, 0x03, 0x00, 4,
+ 'n', 'a', 'i', 'l'
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name);
+
+ _encodeName(encoder, dictionary);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxName_Release(&name);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Local, _encodePayload)
+{
+ uint8_t payload[] = { 0xf1, 0xf2, 0xf3 };
+ uint8_t encoded[] = {
+ 0x00, 0x01, 0x00, 3,
+ 0xf1, 0xf2, 0xf3
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(payload, sizeof(payload), 0, sizeof(payload));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, buffer);
+
+ _encodePayload(encoder, dictionary);
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&buffer);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Local, _encodePayloadType)
+{
+ CCNxPayloadType type = CCNxPayloadType_LINK;
+
+ uint8_t encoded[] = {
+ 0x00, 0x05, 0x00, 1,
+ CCNxCodecSchemaV1Types_PayloadType_Link
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE, type);
+
+ _encodePayloadType(encoder, dictionary);
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeExpiryTime)
+{
+ uint64_t expiry = 0x123456789ABCDEF0ULL;
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 8,
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC, 0xDE, 0xF0
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME, expiry);
+
+ _encodeExpiryTime(encoder, dictionary);
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeEndChunkNumber)
+{
+ uint64_t endChunkNumber = 0x818283ULL;
+ uint8_t encoded[] = {
+ 0x00, 0x19, 0x00, 3,
+ 0x81, 0x82, 0x83
+ };
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT, endChunkNumber);
+
+ _encodeEndChunkNumber(encoder, dictionary);
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeKeyIdRestriction)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x02, 0x00, 0x24,
+ 0x00, 0x01, 0x00, 0x20,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded));
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutObject(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION, hash);
+
+ _encodeKeyIdRestriction(encoder, dictionary);
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&buffer);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+ parcCryptoHash_Release(&hash);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeContentObjectHashRestriction)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x03, 0x00, 0x24,
+ 0x00, 0x01, 0x00, 0x20,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded));
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ccnxTlvDictionary_PutObject(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION, hash);
+
+ _encodeContentObjectHashRestriction(encoder, dictionary);
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "buffers do not match")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&buffer);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&dictionary);
+ parcCryptoHash_Release(&hash);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(UnknownType)
+{
+ LONGBOW_RUN_TEST_CASE(UnknownType, Unknown);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(UnknownType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownType)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(UnknownType, Unknown)
+{
+ CCNxTlvDictionary *unknown = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, 1);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1MessageEncoder_Encode(encoder, unknown);
+ assertTrue(length < 0, "Did not get error return when encoding unknown type");
+
+ CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder);
+ assertNotNull(error, "encoder did not set the error");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&unknown);
+}
+
+// ==================================================================================
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_MessageEncoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c
new file mode 100755
index 00000000..8a33a0e2
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_NameCodec.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(ccnxTlvCodec_Name)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Name)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Name)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecName_Decode_RightType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecName_Decode_WrongType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecName_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecName_Decode_RightType)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("brandywine");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer);
+ CCNxName *truth = ccnxName_Append(ccnxName_Create(), segment);
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buffer);
+
+ uint8_t decodeBytes[] = { 0x10, 0x20, 0x00, 0x0E, 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer);
+ CCNxName *test = ccnxCodecSchemaV1NameCodec_Decode(decoder, 0x1020);
+
+ assertTrue(ccnxName_Equals(truth, test), "Name segments do not match");
+
+ ccnxName_Release(&test);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&decodeBuffer);
+ ccnxName_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecName_Decode_WrongType)
+{
+ uint8_t decodeBytes[] = { 0x10, 0x20, 0x00, 0x0E, 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer);
+ CCNxName *test = ccnxCodecSchemaV1NameCodec_Decode(decoder, 0xFFFF);
+
+ assertNull(test, "Name should have returned NULL because the name type does not match");
+ assertTrue(ccnxCodecTlvDecoder_Position(decoder) == 0, "Position should not have moved, expected 0, got %zu", ccnxCodecTlvDecoder_Position(decoder));
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&decodeBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecName_Encode)
+{
+ uint8_t truthBytes[] = { 0x10, 0x20, 0x00, 0x0E, 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ PARCBuffer *buffer = parcBuffer_WrapCString("brandywine");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer);
+
+ CCNxName *name = ccnxName_Append(ccnxName_Create(), segment);
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buffer);
+
+ ccnxCodecSchemaV1NameCodec_Encode(encoder, 0x1020, name);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers do not match\n");
+ printf("Excpected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers do not match");
+ }
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Name);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c
new file mode 100755
index 00000000..77800055
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_NameSegmentCodec.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h>
+
+LONGBOW_TEST_RUNNER(ccnxTlvCodec_Name)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Name)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Name)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_TLShort);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_VShort);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("brandywine");
+ CCNxNameSegment *truth = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer);
+ parcBuffer_Release(&buffer);
+
+ uint8_t decodeBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer);
+ CCNxNameSegment *test = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder);
+
+ assertTrue(ccnxNameSegment_Equals(truth, test), "Name segments do not match");
+
+ ccnxNameSegment_Release(&test);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&decodeBuffer);
+ ccnxNameSegment_Release(&truth);
+}
+
+/**
+ * In this case, there are not enough bytes in the buffer to decode the T and L
+ */
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_TLShort)
+{
+ uint8_t decodeBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a' };
+ PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer);
+ CCNxNameSegment *test = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder);
+
+ assertNull(test, "Name segments should have been null because there are not enough bytes in buffer");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&decodeBuffer);
+}
+
+/**
+ * In this case, we decode the T and L, but there are not enough bytes for the V
+ */
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_VShort)
+{
+ uint8_t decodeBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00 };
+ PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer);
+ CCNxNameSegment *test = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder);
+
+ assertNull(test, "Name segments should have been null because there are not enough bytes in buffer");
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&decodeBuffer);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Encode)
+{
+ uint8_t truthBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ PARCBuffer *buffer = parcBuffer_WrapCString("brandywine");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer);
+ parcBuffer_Release(&buffer);
+
+ ccnxCodecSchemaV1NameSegmentCodec_Encode(encoder, segment);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers do not match");
+
+ parcBuffer_Release(&test);
+ ccnxNameSegment_Release(&segment);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Name);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c
new file mode 100644
index 00000000..abe47608
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_OptionalHeadersDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <inttypes.h>
+
+#include <LongBow/unit-test.h>
+
+typedef struct test_data {
+ PARCBuffer *optionalHeader;
+ CCNxCodecTlvDecoder *decoder;
+ CCNxTlvDictionary *dictionary;
+
+ // truth table
+ PARCBuffer *interestLifetime;
+ PARCBuffer *cacheTime;
+ PARCBuffer *interestFrag;
+ PARCBuffer *objectFrag;
+ PARCBuffer *customHeader;
+
+ // the key for the customHeader
+ uint16_t customHeaderType;
+} TestData;
+
+/**
+ * A packet with all the defined optional headers plus one custom header
+ * This is not actually a packet one would see in real life as it has
+ * headers from both an Interest and a Content Object
+ */
+static uint8_t packet_with_headers[] = {
+ 0x01, 0x01, 0x00, 120, // ver = 1, type = interest, length = 120
+ 0x01, 0x00, 0x00, 88, // hopLimit = 1, reserved = 0, header length = 88
+ // ------------------------
+ // byte 8
+ 0x00, 0x01, 0x00, 0x08, // Interest Lifetime (type 1)
+ 0x20, 0x30, 0x40, 0x50, // 0x2030405060708090
+ 0x60, 0x70, 0x80, 0x90,
+ // ------------------------
+ // byte 20
+ 0x00, 0x02, 0x00, 0x08, // Recommended Cache Time (type 2)
+ 0x21, 0x31, 0x41, 0x51, // 0x2030405060708090
+ 0x61, 0x71, 0x81, 0x91,
+ // ------------------------
+ // byte 32
+ 0x00, 0x03, 0x00, 0x0C, // Interest Fragment (type 3)
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708
+ 0x05, 0xDC, 0x04, 0x00, // MTU 1500, fragcnt 4, fragnum 0
+ // ------------------------
+ // byte 48
+ 0x00, 0x04, 0x00, 20, // ContentObject Fragment (type 4)
+ 0xC1, 0xC2, 0xC3, 0xC4,
+ 0xC5, 0xC6, 0xC7, 0xC8, // fragment 0xC1C2C3C4C5C6C7C8
+ 0x05, 0xDC, 0x04, 0x00, // MTU 1500, fragcnt 4, fragnum 0
+ 0xD1, 0xD2, 0xD3, 0xD4,
+ 0xD5, 0xD6, 0xD7, 0xD8, // fragment 0xD1D2D3D4D5D6D7D8
+ // ------------------------
+ // byte 72
+ 0x01, 0x00, 0x00, 12, // Custom header (type 256), length 12
+ 0xA0, 0xA1, 0xA2, 0xA3,
+ 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xAA, 0xAB,
+ // ------------------------
+ // byte 88
+ 0x00, 0x01, 0x00, 29, // type = interest, length = 29
+ // ------------------------
+ 0x00, 0x00, 0x00, 0x10, // type = name, length = 16
+ 0x00, 0x02, 0x00, 0x04, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+ // ------------------------
+ 0x00, 0x01, 0x00, 0x04, // type = keyid, length = 4
+ 0xA0, 0xB0, 0xC0, 0xD0, // 0xA0B0C0D0
+ // ------------------------
+ // byte 120
+};
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ // setup the decoder and decode the optional headers
+ data->optionalHeader = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 8, 88);
+ data->decoder = ccnxCodecTlvDecoder_Create(data->optionalHeader);
+ data->dictionary = ccnxTlvDictionary_Create(10, 5);
+
+ // setup the truth values
+ data->interestLifetime = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 12, 20);
+ data->cacheTime = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 24, 32);
+
+ data->interestFrag = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 36, 48);
+ data->objectFrag = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 52, 72);
+
+ data->customHeader = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 76, 88);
+ data->customHeaderType = 0x0100;
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ ccnxTlvDictionary_Release(&data->dictionary);
+ ccnxCodecTlvDecoder_Destroy(&data->decoder);
+ parcBuffer_Release(&data->optionalHeader);
+
+ parcBuffer_Release(&data->interestLifetime);
+ parcBuffer_Release(&data->cacheTime);
+ parcBuffer_Release(&data->interestFrag);
+ parcBuffer_Release(&data->objectFrag);
+ parcBuffer_Release(&data->customHeader);
+
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_OptionalHeadersDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_OptionalHeadersDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_OptionalHeadersDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_Decode_TooLong);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader_Missing);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader_Missing);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/**
+ * One of the TLVs will extend beyond the end of the buffer. Should fail.
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_Decode_TooLong)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // Make one of the fields 255 bytes
+ uint8_t original = packet_with_headers[10];
+ packet_with_headers[10] = 0xFF;
+ bool success = ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary);
+
+ // now set it back
+ packet_with_headers[10] = original;
+
+ assertFalse(success, "Should have failed to parse when a TLV exceeds bounary");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary);
+ PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(data->dictionary);
+ assertTrue(parcBuffer_Equals(test, data->objectFrag), "Wrong value")
+ {
+ printf("Expected: \n");
+ parcBuffer_Display(data->objectFrag, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary);
+ PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(data->dictionary);
+ assertTrue(parcBuffer_Equals(test, data->interestFrag), "Wrong value")
+ {
+ printf("Expected: \n");
+ parcBuffer_Display(data->interestFrag, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary);
+ uint64_t lifetime = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader(data->dictionary);
+
+ uint64_t trueLifetime = 0;
+ ccnxCodecTlvUtilities_GetVarInt(data->interestLifetime, parcBuffer_Remaining(data->interestLifetime), &trueLifetime);
+
+ assertTrue(trueLifetime == lifetime, "wrong value, expected %" PRIx64 " got %" PRIx64, trueLifetime, lifetime);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary);
+ uint64_t cachetime = ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader(data->dictionary);
+
+ uint64_t trueCachetime = 0;
+ ccnxCodecTlvUtilities_GetVarInt(data->cacheTime, parcBuffer_Remaining(data->cacheTime), &trueCachetime);
+
+ assertTrue(trueCachetime == cachetime, "wrong value, expected %" PRIx64 " got %" PRIx64, trueCachetime, cachetime);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary);
+ PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(data->dictionary, data->customHeaderType);
+ assertTrue(parcBuffer_Equals(test, data->customHeader), "Wrong value for header type %02X", data->customHeaderType)
+ {
+ printf("Expected: \n");
+ parcBuffer_Display(data->customHeader, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+}
+
+// ========
+// test for missing values
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(data->dictionary);
+ assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(data->dictionary);
+ assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ bool exists = ccnxTlvDictionary_IsValueInteger(data->dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+ assertFalse(exists, "Dictionary reports it has a missing field");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool exists = ccnxTlvDictionary_IsValueInteger(data->dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime);
+ assertFalse(exists, "Dictionary reports it has a missing field");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(data->dictionary, data->customHeaderType);
+ assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_OptionalHeadersDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c
new file mode 100644
index 00000000..1950eef2
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_OptionalHeadersEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h>
+
+#include "testrig_encoder.c"
+
+static TruthTableEntry
+TRUTHTABLENAME(interest_optional_headers)[] =
+{
+ { .wellKnownType = false, .indexOrKey = V1_MANIFEST_INT_OPTHEAD, .bodyManifest = true, .extent = { 8, 28 } }, // index = 0
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } }, // index = 1
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_LIFETIME, .bodyManifest = false, .extent = { 28, 8 } }, // index = 2
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+static TruthTableEntry
+TRUTHTABLENAME(contentobject_optional_headers)[] =
+{
+ { .wellKnownType = false, .indexOrKey = V1_MANIFEST_OBJ_OPTHEAD, .bodyManifest = true, .extent = { 8, 36 } }, // 0
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_E2EFRAG, .bodyManifest = false, .extent = { 12, 20 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_RecommendedCacheTime, .bodyManifest = false, .extent = { 36, 8 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV0_OptionalHeadersEncoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Interest);
+ LONGBOW_RUN_TEST_FIXTURE(ContentObject);
+ LONGBOW_RUN_TEST_FIXTURE(UnknownType);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV0_OptionalHeadersEncoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV0_OptionalHeadersEncoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ==================================================================================
+
+LONGBOW_TEST_FIXTURE(Interest)
+{
+ LONGBOW_RUN_TEST_CASE(Interest, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Interest)
+{
+ longBowTestCase_SetClipBoardData(testCase,
+ commonSetup(v1_interest_nameA,
+ sizeof(v1_interest_nameA),
+ TRUTHTABLENAME(interest_optional_headers),
+ V1_MANIFEST_INT_OPTHEAD));
+
+ // commonSetup will not add headers...
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ addBuffer(data, data->dictionary, TRUTHTABLENAME(interest_optional_headers)[1].extent.offset, TRUTHTABLENAME(interest_optional_headers)[1].extent.offset + TRUTHTABLENAME(interest_optional_headers)[1].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG);
+
+ addBuffer(data, data->dictionary, TRUTHTABLENAME(interest_optional_headers)[2].extent.offset, TRUTHTABLENAME(interest_optional_headers)[2].extent.offset + TRUTHTABLENAME(interest_optional_headers)[2].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Interest)
+{
+ testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Interest, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ssize_t length = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(data->encoder, data->dictionary);
+ assertTrue(length >= 0, "Error on Encode: length %zd", length);
+ testCompareEncoderToBuffer(data->encoder, data->memoryRegion);
+}
+
+// ==================================================================================
+
+LONGBOW_TEST_FIXTURE(ContentObject)
+{
+ LONGBOW_RUN_TEST_CASE(ContentObject, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ContentObject)
+{
+ longBowTestCase_SetClipBoardData(testCase,
+ commonSetup(v1_content_nameA_crc32c,
+ sizeof(v1_content_nameA_crc32c),
+ TRUTHTABLENAME(contentobject_optional_headers),
+ V1_MANIFEST_OBJ_OPTHEAD));
+
+ // commonSetup will not add headers...
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ addBuffer(data, data->dictionary, TRUTHTABLENAME(contentobject_optional_headers)[1].extent.offset, TRUTHTABLENAME(contentobject_optional_headers)[1].extent.offset + TRUTHTABLENAME(contentobject_optional_headers)[1].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG);
+
+ addBuffer(data, data->dictionary, TRUTHTABLENAME(contentobject_optional_headers)[2].extent.offset, TRUTHTABLENAME(contentobject_optional_headers)[2].extent.offset + TRUTHTABLENAME(contentobject_optional_headers)[2].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime);
+
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject)
+{
+ testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(ContentObject, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ssize_t length = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(data->encoder, data->dictionary);
+ assertTrue(length >= 0, "Error on Encode: length %zd", length);
+ testCompareEncoderToBuffer(data->encoder, data->memoryRegion);
+}
+
+// ==================================================================================
+
+LONGBOW_TEST_FIXTURE(UnknownType)
+{
+ LONGBOW_RUN_TEST_CASE(UnknownType, Unknown);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(UnknownType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownType)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(UnknownType, Unknown)
+{
+ CCNxTlvDictionary *unknown = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, 1);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(encoder, unknown);
+ assertTrue(length < 0, "Did not get error return when encoding unknown type");
+
+ CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder);
+ assertNotNull(error, "encoder did not set the error");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&unknown);
+}
+
+// ==================================================================================
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV0_OptionalHeadersEncoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c
new file mode 100755
index 00000000..42d5be41
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c
@@ -0,0 +1,684 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Decode whole packets then spot-check that fields from each section appear. We don't need
+ * to exhastively test here, as the individual decoders are exhaustively tested.
+ *
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_PacketDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h>
+
+#include "testrig_packetwrapper.c"
+
+#include <ccnx/common/internal/ccnx_ContentObjectFacadeV1.h>
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_PacketDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(ContentObject);
+ LONGBOW_RUN_TEST_FIXTURE(Control);
+ LONGBOW_RUN_TEST_FIXTURE(Interest);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_PacketDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_PacketDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(ContentObject)
+{
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_FixedHeader);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_Name);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_ExpiryTime);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationAlg_KeyId);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationPayload);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_zero_payload);
+ LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_no_payload);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ContentObject)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_FixedHeader)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+
+ // leave the FixedHeader buffer at position 0
+ parcBuffer_Rewind(fixedHeader);
+
+ PARCBuffer *trueFixedHeader = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, 8, 0, 8);
+ assertTrue(parcBuffer_Equals(fixedHeader, trueFixedHeader), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueFixedHeader, 3);
+ printf("Got\n");
+ parcBuffer_Display(fixedHeader, 3);
+ }
+
+ parcBuffer_Release(&trueFixedHeader);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_Name)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ 0,
+ sizeof(v1_content_nameA_keyid1_rsasha256));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ CCNxName *name = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+ CCNxName *trueName = ccnxName_CreateFromCString(v1_content_nameA_keyid1_rsasha256_URI);
+
+ assertTrue(ccnxName_Equals(name, trueName), "Buffers not equal")
+ {
+ printf("Expected\n");
+ ccnxName_Display(trueName, 3);
+ printf("Got\n");
+ ccnxName_Display(name, 3);
+ }
+
+ ccnxName_Release(&trueName);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_ExpiryTime)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ uint64_t expiryTime = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME);
+
+ TlvExtent expiryExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_EXPIRY_TIME);
+
+ parcBuffer_SetPosition(packetBuffer, expiryExtent.offset);
+ uint64_t trueTime;
+ ccnxCodecTlvUtilities_GetVarInt(packetBuffer, expiryExtent.length, &trueTime);
+
+ assertTrue(expiryTime == trueTime, "Wrong time, expected %" PRIx64 " got %" PRIx64, trueTime, expiryTime);
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationAlg_KeyId)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID);
+
+ TlvExtent keyidExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_KEYID);
+ PARCBuffer *trueKeyid = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), keyidExtent.offset, keyidExtent.offset + keyidExtent.length);
+
+ assertTrue(parcBuffer_Equals(keyid, trueKeyid), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueKeyid, 3);
+ printf("Got\n");
+ parcBuffer_Display(keyid, 3);
+ }
+
+ parcBuffer_Release(&trueKeyid);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationPayload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_SIGBITS);
+ PARCBuffer *truePayload = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truePayload, 3);
+ printf("Got\n");
+ parcBuffer_Display(validationPayload, 3);
+ }
+
+ parcBuffer_Release(&truePayload);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_zero_payload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_zero_payload, sizeof(v1_content_zero_payload), 0, sizeof(v1_content_zero_payload));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ CCNxName *testName = CCNxContentObjectFacadeV1_Implementation.getName(dictionary);
+ assertNotNull(testName, "Got null name on decode");
+
+ PARCBuffer *testPayload = CCNxContentObjectFacadeV1_Implementation.getPayload(dictionary);
+ assertNotNull(testPayload, "got null payload")
+ assertTrue(parcBuffer_Remaining(testPayload) == 0, "Wrong length, expected 0 got %zu", parcBuffer_Remaining(testPayload));
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(ContentObject, ContentObject_no_payload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_no_payload, sizeof(v1_content_no_payload), 0, sizeof(v1_content_no_payload));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ CCNxName *test = CCNxContentObjectFacadeV1_Implementation.getName(dictionary);
+ assertNotNull(test, "Got null name on decode");
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Control)
+{
+ LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_FixedHeader);
+ LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_Payload);
+ LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationAlg_CryptoSuite);
+ LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationPayload);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Control)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Control)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_FixedHeader)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+
+ // leave the FixedHeader buffer at position 0
+ parcBuffer_Rewind(fixedHeader);
+
+ PARCBuffer *trueFixedHeader = parcBuffer_Wrap(v1_cpi_add_route_crc32c, 8, 0, 8);
+ assertTrue(parcBuffer_Equals(fixedHeader, trueFixedHeader), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueFixedHeader, 3);
+ printf("Got\n");
+ parcBuffer_Display(fixedHeader, 3);
+ }
+
+ parcBuffer_Release(&trueFixedHeader);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_Payload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+
+ TlvExtent validationPayloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_cpi_add_route_crc32c), V1_MANIFEST_CPI_SIGBITS);
+ PARCBuffer *trueValidationPayload = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), validationPayloadExtent.offset, validationPayloadExtent.offset + validationPayloadExtent.length);
+
+ assertTrue(parcBuffer_Equals(test, trueValidationPayload), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueValidationPayload, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&trueValidationPayload);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationAlg_CryptoSuite)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCCryptoSuite test = (PARCCryptoSuite) ccnxValidationFacadeV1_GetCryptoSuite(dictionary);
+ PARCCryptoSuite trueCryptoSuite = PARCCryptoSuite_NULL_CRC32C;
+
+ assertTrue(test == trueCryptoSuite, "Wrong crypto suite, expected %d got %d", trueCryptoSuite, test);
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationPayload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_cpi_add_route_crc32c), V1_MANIFEST_CPI_SIGBITS);
+ PARCBuffer *truePayload = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truePayload, 3);
+ printf("Got\n");
+ parcBuffer_Display(validationPayload, 3);
+ }
+
+ parcBuffer_Release(&truePayload);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Interest)
+{
+ LONGBOW_RUN_TEST_CASE(Interest, interest_bad_message_length);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_FixedHeader);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_Lifetime);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_Name);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_ValidationAlg_KeyId);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_ValidationPayload);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_nameA_crc32c_ValidationAlg_CryptoSuite);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_nameA_crc32c_ValidationPayload);
+ LONGBOW_RUN_TEST_CASE(Interest, ccnxCodecSchemaV1PacketDecoder_BufferDecode);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_bad_validation_alg);
+ LONGBOW_RUN_TEST_CASE(Interest, interest_validation_alg_overrun);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Interest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Interest)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Interest, interest_bad_message_length)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_bad_message_length, sizeof(v1_interest_bad_message_length), 0, sizeof(v1_interest_bad_message_length));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertFalse(success, "Should have seen and error on decode");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Error not set when bad decode");
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_all_fields_FixedHeader)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+
+ // leave the FixedHeader buffer at position 0
+ parcBuffer_Rewind(fixedHeader);
+
+ PARCBuffer *trueFixedHeader = parcBuffer_Wrap(v1_interest_all_fields, 8, 0, 8);
+ assertTrue(parcBuffer_Equals(fixedHeader, trueFixedHeader), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueFixedHeader, 3);
+ printf("Got\n");
+ parcBuffer_Display(fixedHeader, 3);
+ }
+
+ parcBuffer_Release(&trueFixedHeader);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_all_fields_Lifetime)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ uint64_t lifetime = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime);
+
+ TlvExtent lifetimeExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_LIFETIME);
+
+ parcBuffer_SetPosition(packetBuffer, lifetimeExtent.offset);
+ uint64_t trueTime;
+ ccnxCodecTlvUtilities_GetVarInt(packetBuffer, lifetimeExtent.length, &trueTime);
+
+ assertTrue(lifetime == trueTime, "Wrong time, expected %" PRIx64 " got %" PRIx64, trueTime, lifetime);
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_all_fields_Name)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ CCNxName *name = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+ CCNxName *trueName = ccnxName_CreateFromCString(v1_interest_all_fields_URI);
+
+ assertTrue(ccnxName_Equals(name, trueName), "Buffers not equal")
+ {
+ printf("Expected\n");
+ ccnxName_Display(trueName, 3);
+ printf("Got\n");
+ ccnxName_Display(name, 3);
+ }
+
+ ccnxName_Release(&trueName);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+/*
+ * This packet does not have a validation section, so the test is that its missing
+ */
+LONGBOW_TEST_CASE(Interest, interest_all_fields_ValidationAlg_KeyId)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID);
+ assertNull(keyid, "Got a non-null keyid from a packet without one");
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+/*
+ * Packet does not have validation, test for missing
+ */
+LONGBOW_TEST_CASE(Interest, interest_all_fields_ValidationPayload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *payload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+ assertNull(payload, "Got a non-null validation payload from a packet without one");
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_nameA_crc32c_ValidationAlg_CryptoSuite)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCCryptoSuite suite = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ PARCCryptoSuite trueSuite = PARCCryptoSuite_NULL_CRC32C;
+
+ assertTrue(suite == trueSuite, "Wrong crypto suite, expected %d got %d", trueSuite, suite);
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_nameA_crc32c_ValidationPayload)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload);
+ PARCBuffer *truePayload = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truePayload, 3);
+ printf("Got\n");
+ parcBuffer_Display(validationPayload, 3);
+ }
+
+ parcBuffer_Release(&truePayload);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, ccnxCodecSchemaV1PacketDecoder_BufferDecode)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c));
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_BufferDecode(packetBuffer, dictionary);
+ assertTrue(success, "Error on decode");
+
+ PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+
+ TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload);
+ PARCBuffer *truePayload = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), payloadExtent.offset, payloadExtent.offset + payloadExtent.length);
+
+ assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truePayload, 3);
+ printf("Got\n");
+ parcBuffer_Display(validationPayload, 3);
+ }
+
+ parcBuffer_Release(&truePayload);
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_bad_validation_alg)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_bad_validation_alg, sizeof(v1_interest_bad_validation_alg), 0, sizeof(v1_interest_bad_validation_alg));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertFalse(success, "Should have seen and error on decode");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Error not set when bad decode");
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+LONGBOW_TEST_CASE(Interest, interest_validation_alg_overrun)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_validation_alg_overrun, sizeof(v1_interest_validation_alg_overrun), 0, sizeof(v1_interest_validation_alg_overrun));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary);
+ assertFalse(success, "Should have seen and error on decode");
+
+ CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder);
+ assertNotNull(error, "Error not set when bad decode");
+
+ parcBuffer_Release(&packetBuffer);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+}
+
+// =========================================================================
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_PacketDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c
new file mode 100755
index 00000000..eb79502e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c
@@ -0,0 +1,1054 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_PacketEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h>
+
+#include "testrig_encoder.c"
+
+#include <ccnx/common/ccnx_Interest.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+
+#include <ccnx/common/validation/ccnxValidation_CRC32C.h>
+
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_PacketEncoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(ContentObject);
+ LONGBOW_RUN_TEST_FIXTURE(Interest);
+ LONGBOW_RUN_TEST_FIXTURE(InterestReturn);
+ LONGBOW_RUN_TEST_FIXTURE(Control);
+ LONGBOW_RUN_TEST_FIXTURE(UnknownType);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_PacketEncoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_PacketEncoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(ContentObject)
+{
+ LONGBOW_RUN_TEST_CASE(ContentObject, v1_content_nameA_keyid1_rsasha256);
+ LONGBOW_RUN_TEST_CASE(ContentObject, zero_length_payload);
+ LONGBOW_RUN_TEST_CASE(ContentObject, null_payload);
+ LONGBOW_RUN_TEST_CASE(ContentObject, no_cryptosuite);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ContentObject)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/*
+ * Make a dictionary equivalent to v1_content_nameA_keyid1_rsasha256 and encode it then compare
+ */
+LONGBOW_TEST_CASE(ContentObject, v1_content_nameA_keyid1_rsasha256)
+{
+ CCNxName *name = ccnxName_CreateFromCString(v1_content_nameA_keyid1_rsasha256_URI);
+
+ TlvExtent payloadExtent =
+ getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_PAYLOAD);
+ PARCBuffer *payload = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ payloadExtent.offset,
+ payloadExtent.offset + payloadExtent.length);
+
+ CCNxTlvDictionary *message =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name, CCNxPayloadType_KEY, payload);
+
+ TlvExtent fragmentExtent =
+ getTruthTableHeaderExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_E2EFRAG);
+ PARCBuffer *fragment = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ fragmentExtent.offset,
+ fragmentExtent.offset + fragmentExtent.length);
+ ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG, fragment);
+
+ uint64_t expiryTime = 1388534400000ULL;
+ ccnxContentObject_SetExpiryTime(message, expiryTime);
+
+ uint64_t endChunkNumber = 0x06050403;
+ ccnxContentObject_SetFinalChunkNumber(message, endChunkNumber);
+
+ TlvExtent keyIdExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_KEYID);
+ PARCBuffer *keyid = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ keyIdExtent.offset,
+ keyIdExtent.offset + keyIdExtent.length);
+
+ TlvExtent keyExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_PUBKEY);
+ PARCBuffer *key = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ keyExtent.offset,
+ keyExtent.offset + keyExtent.length);
+
+ ccnxValidationFacadeV1_SetCryptoSuite(message, PARCCryptoSuite_RSA_SHA256);
+ ccnxValidationFacadeV1_SetKeyId(message, keyid);
+ ccnxValidationFacadeV1_SetPublicKey(message, key);
+
+ TlvExtent sigExtent =
+ getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_SIGBITS);
+ PARCBuffer *sig = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ sigExtent.offset,
+ sigExtent.offset + sigExtent.length);
+
+ ccnxValidationFacadeV1_SetPayload(message, sig);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertFalse(length < 0, "Got encoding error: %s",
+ ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ assertTrue(length == sizeof(v1_content_nameA_keyid1_rsasha256),
+ "Wrong length, expected %zu got %zd", sizeof(v1_content_nameA_keyid1_rsasha256), length);
+
+ // verify
+ PARCBuffer *truth = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256,
+ sizeof(v1_content_nameA_keyid1_rsasha256),
+ 0,
+ sizeof(v1_content_nameA_keyid1_rsasha256));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+
+ uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0);
+ uint8_t *testOverlay = parcBuffer_Overlay(test, 0);
+
+ for (ssize_t i = 0; i < length; i++) {
+ if (truthOverlay[i] != testOverlay[i]) {
+ printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x\n", i, truthOverlay[i], testOverlay[i]);
+ break;
+ }
+ }
+ }
+
+ // cleanup
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&sig);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&keyid);
+ parcBuffer_Release(&payload);
+ parcBuffer_Release(&fragment);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&message);
+}
+
+
+LONGBOW_TEST_CASE(ContentObject, zero_length_payload)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/no/payload");
+ PARCBuffer *payload = parcBuffer_Allocate(0);
+
+ CCNxTlvDictionary *message =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name, CCNxPayloadType_DATA, payload);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertNotNull(encoded, "got null output buffer");
+
+ parcBuffer_Display(encoded, 3);
+
+ parcBuffer_Release(&encoded);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(ContentObject, null_payload)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/no/payload");
+
+ CCNxTlvDictionary *message =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name, CCNxPayloadType_DATA, NULL);
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertNotNull(encoded, "got null output buffer");
+
+ parcBuffer_Release(&encoded);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+ ccnxName_Release(&name);
+}
+
+/*
+ * A content object without a cryptosuite should not be signed
+ */
+LONGBOW_TEST_CASE(ContentObject, no_cryptosuite)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/no/payload");
+
+ CCNxTlvDictionary *message =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name, CCNxPayloadType_DATA, NULL);
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertNotNull(encoded, "got null output buffer");
+
+ // it should be 33 bytes without a signature
+ assertTrue(parcBuffer_Remaining(encoded) == 33, "Wrong length exepcted 33 got %zu", parcBuffer_Remaining(encoded));
+
+ parcBuffer_Release(&encoded);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+ ccnxName_Release(&name);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Interest)
+{
+ LONGBOW_RUN_TEST_CASE(Interest, v1_interest_nameA_crc32c);
+ LONGBOW_RUN_TEST_CASE(Interest, v1_interest_nameA_crc32c_IoVec);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Interest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Interest)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/*
+ * Make an interest equivalent to v1_interest_nameA_crc32c and encode it
+ */
+LONGBOW_TEST_CASE(Interest, v1_interest_nameA_crc32c)
+{
+ CCNxName *name = ccnxName_CreateFromCString(v1_interest_nameA_crc32c_URI);
+
+ CCNxTlvDictionary *message =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, 32);
+
+ TlvExtent fragmentExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_E2EFRAG);
+ PARCBuffer *fragment = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), fragmentExtent.offset, fragmentExtent.offset + fragmentExtent.length);
+ ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG, fragment);
+
+ ccnxValidationFacadeV1_SetCryptoSuite(message, PARCCryptoSuite_NULL_CRC32C);
+
+ TlvExtent sigExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload);
+ PARCBuffer *sig = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), sigExtent.offset, sigExtent.offset + sigExtent.length);
+
+ ccnxValidationFacadeV1_SetPayload(message, sig);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ assertTrue(length == sizeof(v1_interest_nameA_crc32c), "Wrong length, expected %zu got %zd", sizeof(v1_interest_nameA_crc32c), length);
+
+ // verify
+ PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+
+ uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0);
+ uint8_t *testOverlay = parcBuffer_Overlay(test, 0);
+
+ for (ssize_t i = 0; i < length; i++) {
+ if (truthOverlay[i] != testOverlay[i]) {
+ printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x", i, truthOverlay[i], testOverlay[i]);
+ break;
+ }
+ }
+ }
+
+ // cleanup
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&sig);
+ parcBuffer_Release(&fragment);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&message);
+}
+
+/*
+ * Make an interest equivalent to v1_interest_nameA_crc32c and encode it
+ */
+LONGBOW_TEST_CASE(Interest, v1_interest_nameA_crc32c_IoVec)
+{
+ CCNxName *name = ccnxName_CreateFromCString(v1_interest_nameA_crc32c_URI);
+
+ CCNxTlvDictionary *message =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, 32);
+
+ TlvExtent fragmentExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_E2EFRAG);
+ PARCBuffer *fragment = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), fragmentExtent.offset, fragmentExtent.offset + fragmentExtent.length);
+ ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG, fragment);
+
+ ccnxValidationFacadeV1_SetCryptoSuite(message, PARCCryptoSuite_NULL_CRC32C);
+
+ TlvExtent sigExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload);
+ PARCBuffer *sig = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), sigExtent.offset, sigExtent.offset + sigExtent.length);
+
+ ccnxValidationFacadeV1_SetPayload(message, sig);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(message, NULL);
+ assertNotNull(iovec, "Got null iovec from ccnxCodecSchemaV1PacketEncoder_DictionaryEncode");
+
+ size_t length = ccnxCodecNetworkBufferIoVec_Length(iovec);
+ assertTrue(length == sizeof(v1_interest_nameA_crc32c), "Wrong length, expected %zu got %zd", sizeof(v1_interest_nameA_crc32c), length);
+
+ // verify
+ PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c));
+
+ int iovecCount = ccnxCodecNetworkBufferIoVec_GetCount(iovec);
+ PARCBuffer *test = parcBuffer_Allocate(length);
+ const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray(iovec);
+ for (int i = 0; i < iovecCount; i++) {
+ parcBuffer_PutArray(test, array[i].iov_len, array[i].iov_base);
+ }
+ parcBuffer_Flip(test);
+
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+
+ uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0);
+ uint8_t *testOverlay = parcBuffer_Overlay(test, 0);
+
+ for (ssize_t i = 0; i < length; i++) {
+ if (truthOverlay[i] != testOverlay[i]) {
+ printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x", i, truthOverlay[i], testOverlay[i]);
+ break;
+ }
+ }
+ }
+
+ // cleanup
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&sig);
+ parcBuffer_Release(&fragment);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&message);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(InterestReturn)
+{
+ LONGBOW_RUN_TEST_CASE(InterestReturn, v1_interest_return);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(InterestReturn)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(InterestReturn)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/*
+ * Make an interest return and encode it
+ */
+LONGBOW_TEST_CASE(InterestReturn, v1_interest_return)
+{
+ CCNxName *name = ccnxName_CreateFromCString(v1_interest_nameA_crc32c_URI);
+
+ CCNxInterest *interest =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, 32);
+ ccnxName_Release(&name);
+
+ TlvExtent fragmentExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_E2EFRAG);
+ PARCBuffer *fragment = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), fragmentExtent.offset, fragmentExtent.offset + fragmentExtent.length);
+ ccnxTlvDictionary_PutBuffer(interest, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG, fragment);
+ parcBuffer_Release(&fragment);
+
+ ccnxValidationFacadeV1_SetCryptoSuite(interest, PARCCryptoSuite_NULL_CRC32C);
+
+ TlvExtent sigExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload);
+ PARCBuffer *sig = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), sigExtent.offset, sigExtent.offset + sigExtent.length);
+
+ ccnxValidationFacadeV1_SetPayload(interest, sig);
+ parcBuffer_Release(&sig);
+
+ CCNxTlvDictionary *message =
+ ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_NoResources);
+ ccnxInterest_Release(&interest);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ ssize_t expectedLength = sizeof(v1_interest_nameA_crc32c);
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ assertTrue(length == expectedLength, "Wrong length, expected %zu got %zd", expectedLength, length);
+
+ // verify
+ PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c_returned, sizeof(v1_interest_nameA_crc32c_returned), 0, sizeof(v1_interest_nameA_crc32c_returned));
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+
+ uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0);
+ uint8_t *testOverlay = parcBuffer_Overlay(test, 0);
+
+ for (ssize_t i = 0; i < length; i++) {
+ if (truthOverlay[i] != testOverlay[i]) {
+ printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x\n", i, truthOverlay[i], testOverlay[i]);
+ }
+ }
+ }
+
+ // cleanup
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Control)
+{
+ LONGBOW_RUN_TEST_CASE(Control, payload);
+ LONGBOW_RUN_TEST_CASE(Control, cryptosuite);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Control)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Control)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Control, payload)
+{
+ uint8_t encoded[] = {
+ 0x01, 0xa4, 0x00, 0x22,
+ 0x00, 0x00, 0x00, 0x08,
+
+ 0xbe, 0xef, 0x00, 0x16, // control message
+
+ 0x7b, 0x22, 0x74, 0x68, // {"th
+ 0x69, 0x73, 0x20, 0x69, // is i
+ 0x73, 0x22, 0x3a, 0x22, // s":"
+ 0x61, 0x6e, 0x6e, 0x6f, // anno
+ 0x79, 0x69, 0x6e, 0x67, // ying
+ 0x22, 0x7d // "}
+ };
+
+
+ CCNxTlvDictionary *message = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+
+ PARCJSON *json = parcJSON_Create();
+ parcJSON_AddString(json, "this is", "annoying");
+
+ ccnxTlvDictionary_PutJson(message, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, json);
+ parcJSON_Release(&json);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ // verify
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+
+ uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0);
+ uint8_t *testOverlay = parcBuffer_Overlay(test, 0);
+
+ for (ssize_t i = 0; i < length; i++) {
+ if (truthOverlay[i] != testOverlay[i]) {
+ printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x", i, truthOverlay[i], testOverlay[i]);
+ break;
+ }
+ }
+ }
+
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+ parcBuffer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Control, cryptosuite)
+{
+ uint8_t encoded[] = {
+ 0x01, 0xA4, 0x00, 16,
+ 0x00, 0x00, 0x00, 8,
+ 0xBE, 0xEF, 0x00, 4,
+ 'a', 'b', 'c', 'd',
+ 0x00, 0x03, 0x00, 4,
+ 0x00, 0x02, 0x00, 0
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *payload = parcBuffer_Wrap(encoded, sizeof(encoded), 12, 16);
+
+ CCNxTlvDictionary *message = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+ ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, payload);
+ ccnxValidationCRC32C_Set(message);
+
+ ccnxValidationCRC32C_Set(message);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertNotNull(test, "Got null buffer from encoder");
+ uint8_t testSuite = parcBuffer_GetAtIndex(test, 21);
+ assertTrue(testSuite == 2, "Wrong cryptosuite, expected 2 got %u", testSuite);
+
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+ parcBuffer_Release(&payload);
+ parcBuffer_Release(&truth);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(UnknownType)
+{
+ LONGBOW_RUN_TEST_CASE(UnknownType, unknown);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(UnknownType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownType)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/*
+ * try to encode a message with unknown message type
+ */
+LONGBOW_TEST_CASE(UnknownType, unknown)
+{
+ // this initializes the dictionary to unknown type
+ CCNxTlvDictionary *message = ccnxTlvDictionary_Create(20, 20);
+
+ // encode
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message);
+ assertTrue(length < 0, "Did not get error condition for unknown type");
+
+ CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder);
+ assertNotNull(error, "Did not get an error for invalid encoding");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ ccnxTlvDictionary_Release(&message);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _getHopLimit_Present);
+ LONGBOW_RUN_TEST_CASE(Local, _getHopLimit_Missing);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeFixedHeader_ContentObject);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeFixedHeader_Interest);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeOptionalHeaders);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeMessage_Interest);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeMessage_ContentObject);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeCPI);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeMessage_Unknown);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeValidationAlg_Present);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeValidationAlg_Missing);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeValidationPayload_Present);
+ LONGBOW_RUN_TEST_CASE(Local, _encodeValidationPayload_Missing);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _getHopLimit_Present)
+{
+ uint8_t hoplimit = 77;
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxTlvDictionary_PutInteger(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, hoplimit);
+
+ uint8_t test = _getHopLimit(dict);
+ assertTrue(test == hoplimit, "Got wrong hoplimit, expected %u got %u", hoplimit, test);
+ ccnxTlvDictionary_Release(&dict);
+}
+
+LONGBOW_TEST_CASE(Local, _getHopLimit_Missing)
+{
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ uint8_t test = _getHopLimit(dict);
+ assertTrue(test == CCNxInterestDefault_HopLimit, "Got wrong hoplimit, expected %u got %u", CCNxInterestDefault_HopLimit, test);
+ ccnxTlvDictionary_Release(&dict);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeFixedHeader_ContentObject)
+{
+ uint8_t encoded[] = {
+ 0x01, 0x01, 0x00, 100, // ver = 1, type = content object, length = 100
+ 0x00, 0x00, 0x00, 14, // reserved = 0x0000000, header length = 14
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = _encodeFixedHeader(encoder, dict, CCNxCodecSchemaV1Types_PacketType_ContentObject, 14, 100);
+ assertTrue(length == 8, "wrong length, expected %d got %zd", 8, length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeFixedHeader_Interest)
+{
+ uint8_t encoded[] = {
+ 0x01, 0x00, 0x00, 100, // ver = 1, type = interest, length = 100
+ 0x1f, 0x00, 0x00, 14, // hoplimit = 31, reserved = 0x0000, header length = 14
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxTlvDictionary_PutInteger(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, 31);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = _encodeFixedHeader(encoder, dict, CCNxCodecSchemaV1Types_PacketType_Interest, 14, 100);
+ assertTrue(length == 8, "wrong length, expected %d got %zd", 8, length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeOptionalHeaders)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes)
+ 0xEA, 0xEB,
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxTlvDictionary_PutInteger(dict, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime, 0xEAEB);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ssize_t length = _encodeOptionalHeaders(encoder, dict);
+ assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeMessage_Interest)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x01, 0x00, 13,
+ 0x00, 0x00, 0x00, 9,
+ 0x00, CCNxNameLabelType_NAME, 0x00, 5,
+ 'p', 'o', 'p', 'p', 'y'
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/poppy");
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxTlvDictionary_PutName(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecSchemaV1Types_PacketType packetType;
+ ssize_t length = _encodeMessage(encoder, dict, &packetType);
+ assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length);
+ assertTrue(packetType == CCNxCodecSchemaV1Types_PacketType_Interest, "Wrong packet type, expected %d got %d",
+ CCNxCodecSchemaV1Types_PacketType_Interest, packetType);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeMessage_ContentObject)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x02, 0x00, 13,
+ 0x00, 0x00, 0x00, 9,
+ 0x00, CCNxNameLabelType_NAME, 0x00, 5,
+ 'p', 'o', 'p', 'p', 'y'
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/poppy");
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxTlvDictionary_PutName(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecSchemaV1Types_PacketType packetType;
+ ssize_t length = _encodeMessage(encoder, dict, &packetType);
+ assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length);
+ assertTrue(packetType == CCNxCodecSchemaV1Types_PacketType_ContentObject, "Wrong packet type, expected %d got %d",
+ CCNxCodecSchemaV1Types_PacketType_ContentObject, packetType);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeCPI)
+{
+ uint8_t encoded [] = {
+ 0x00, 0x02, 0x03, 0x99, //
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxValidationCRC32C_Set(dict);
+ ccnxTlvDictionary_PutBuffer(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, truth);
+
+ ssize_t length = _encodeCPI(encoder, dict);
+ assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+/*
+ * This test requires that we set the message type to some unknown value, which we get if
+ * we create a dictionary with ccnxTlvDictionary_Create() and dont call anything to set
+ * the message type. It will be "CCNxTlvDictionary_Unknown".
+ */
+LONGBOW_TEST_CASE(Local, _encodeMessage_Unknown)
+{
+ CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(20, 20);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecSchemaV1Types_PacketType packetType;
+ ssize_t length = _encodeMessage(encoder, dict, &packetType);
+ assertTrue(length < 0, "wrong length, expected negative got %zd", length);
+
+ CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder);
+ assertNotNull(error, "Got null error when an error condition should have been set");
+
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeValidationAlg_Present)
+{
+ uint8_t encoded [] = {
+ 0x00, 0x03, 0x00, 4, // validation alg, length = 4
+ 0x00, 0x02, 0x00, 0x00, // CRC32C
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *truePayload = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxValidationCRC32C_Set(dict);
+ ccnxTlvDictionary_PutBuffer(dict, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, truePayload);
+
+ ssize_t length = _encodeValidationAlg(encoder, dict);
+ assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&truePayload);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeValidationAlg_Missing)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ssize_t length = _encodeValidationAlg(encoder, dict);
+ assertTrue(length == 0, "wrong length, expected %d got %zd", 0, length);
+
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeValidationPayload_Present)
+{
+ uint8_t encoded [] = {
+ 0x00, 0x04, 0x00, 4, // validation payload, length = 4
+ 0x00, 0x02, 0x03, 0x99, //
+ };
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *truePayload = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxValidationCRC32C_Set(dict);
+ ccnxTlvDictionary_PutBuffer(dict, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, truePayload);
+
+ ssize_t length = _encodeValidationPayload(encoder, dict);
+ assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&truePayload);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Local, _encodeValidationPayload_Missing)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ ssize_t length = _encodeValidationPayload(encoder, dict);
+ assertTrue(length == 0, "wrong length, expected %d got %zd", 0, length);
+
+ ccnxTlvDictionary_Release(&dict);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+
+// ==================================================================================
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_PacketEncoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c
new file mode 100755
index 00000000..ccaa8b13
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_TlvDictionary.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_TlvDictionary)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_TlvDictionary)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_TlvDictionary)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateContentObject);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateControl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterest)
+{
+ CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateInterest");
+ assertTrue(ccnxTlvDictionary_IsInterest(test), "Dictionary is not an interest");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema version, expected %d got %d",
+ CCNxTlvDictionary_SchemaVersion_V1,
+ ccnxTlvDictionary_GetSchemaVersion(test));
+ ccnxTlvDictionary_Release(&test);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn)
+{
+ CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn();
+ assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateInterest");
+ assertTrue(ccnxTlvDictionary_IsInterestReturn(test), "Dictionary is not an interest");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema version, expected %d got %d",
+ CCNxTlvDictionary_SchemaVersion_V1,
+ ccnxTlvDictionary_GetSchemaVersion(test));
+ ccnxTlvDictionary_Release(&test);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateContentObject)
+{
+ CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateContentObject");
+ assertTrue(ccnxTlvDictionary_IsContentObject(test), "Dictionary is not a content object");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema version, expected %d got %d",
+ CCNxTlvDictionary_SchemaVersion_V1,
+ ccnxTlvDictionary_GetSchemaVersion(test));
+ ccnxTlvDictionary_Release(&test);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateControl)
+{
+ CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+ assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateControl");
+ assertTrue(ccnxTlvDictionary_IsControl(test), "Dictionary is not a control");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema version, expected %d got %d",
+ CCNxTlvDictionary_SchemaVersion_V1,
+ ccnxTlvDictionary_GetSchemaVersion(test));
+ ccnxTlvDictionary_Release(&test);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_TlvDictionary);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c
new file mode 100755
index 00000000..82cf69d1
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_ValidationDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+
+#include "testrig_packetwrapper.c"
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ValidationDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(DecodeAlg);
+ LONGBOW_RUN_TEST_FIXTURE(DecodePayload);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ValidationDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ValidationDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(DecodeAlg)
+{
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, CRC32C);
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, HMAC_SHA256);
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, RSA_SHA256);
+
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, Cert);
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, PublicKey);
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, KeyId);
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, KeyName);
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, SigTime);
+
+ LONGBOW_RUN_TEST_CASE(DecodeAlg, KeyName_Invalid);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(DecodeAlg)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(DecodeAlg)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, CRC32C)
+{
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C;
+ PARCCryptoSuite parcSuite = PARCCryptoSuite_NULL_CRC32C;
+
+ uint8_t encoded[] = {
+ 0x00, tlvSuite, 0x00, 0,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ assertTrue(test == parcSuite, "Got wrong suite, expected %d got %d", parcSuite, test);
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, HMAC_SHA256)
+{
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256;
+ PARCCryptoSuite parcSuite = PARCCryptoSuite_HMAC_SHA256;
+
+ uint8_t encoded[] = {
+ 0x00, tlvSuite, 0x00, 0,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ assertTrue(test == parcSuite, "Got wrong suite, expected %d got %d", parcSuite, test);
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, RSA_SHA256)
+{
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256;
+ PARCCryptoSuite parcSuite = PARCCryptoSuite_RSA_SHA256;
+
+ uint8_t encoded[] = {
+ 0x00, tlvSuite, 0x00, 0,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ assertTrue(test == parcSuite, "Got wrong suite, expected %d got %d", parcSuite, test);
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, Cert)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 10,
+ 0x00, 0x0C, 0x00, 6,
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded));
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, PublicKey)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 10,
+ 0x00, 0x0B, 0x00, 6,
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded));
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, KeyId)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 10,
+ 0x00, 0x09, 0x00, 6,
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded));
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, KeyName)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 44,
+ 0x00, 0x0E, 0x00, 40,
+ // --- name
+ 0x00, 0x00, 0x00, 16,
+ 0x00, 0x03, 0x00, 5,
+ 'a', 'p', 'p', 'l',
+ 'e',
+ 0x00, 0x03, 0x00, 3,
+ 'p', 'i', 'e',
+ // --- keyid
+ 0x00, 0x01, 0x00, 4,
+ 0xa1, 0xa2, 0xa3, 0xa4,
+ // --- hash
+ 0x00, 0x02, 0x00, 8,
+ 0xb1, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxName *name = ccnxName_CreateFromCString("lci:/3=apple/3=pie");
+ PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 32, 36);
+ PARCBuffer *hash = parcBuffer_Wrap(encoded, sizeof(encoded), 40, 48);
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ // now test the 3 decoded fields
+ CCNxName *testName = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME);
+ assertTrue(ccnxName_Equals(testName, name), "keynames do not match")
+ {
+ printf("Expected\n");
+ ccnxName_Display(name, 3);
+ printf("Got\n");
+ ccnxName_Display(testName, 3);
+ }
+
+ PARCBuffer *testKeyid = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID);
+ assertTrue(parcBuffer_Equals(testKeyid, keyid), "keyid do not match")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(keyid, 3);
+ printf("Got\n");
+ parcBuffer_Display(testKeyid, 3);
+ }
+
+ PARCBuffer *testHash = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH);
+ assertTrue(parcBuffer_Equals(testHash, hash), "keyid do not match")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(hash, 3);
+ printf("Got\n");
+ parcBuffer_Display(testHash, 3);
+ }
+
+ parcBuffer_Release(&keyid);
+ parcBuffer_Release(&hash);
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, KeyName_Invalid)
+{
+ // link is missing the Name
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 24,
+ 0x00, 0x0E, 0x00, 20,
+ // --- keyid
+ 0x00, 0x01, 0x00, 4,
+ 0xa1, 0xa2, 0xa3, 0xa4,
+ // --- hash
+ 0x00, 0x02, 0x00, 8,
+ 0xb1, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertFalse(success, "Should have failed decode as keyname is invalid");
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodeAlg, SigTime)
+{
+ uint64_t sigtime = 0x1122334455667788ULL;
+ uint8_t encoded[] = {
+ 0x00, 0x06, 0x00, 12,
+ 0x00, 0x0F, 0x00, 8,
+ 0x11, 0x22, 0x33, 0x44,
+ 0x55, 0x66, 0x77, 0x88
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary);
+ assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ uint64_t test = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME);
+ assertTrue(test == sigtime, "Wrong sig time, expected %" PRIx64 ", got %" PRIx64, sigtime, test);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(DecodePayload)
+{
+ LONGBOW_RUN_TEST_CASE(DecodePayload, payload);
+ LONGBOW_RUN_TEST_CASE(DecodePayload, payload_zero);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(DecodePayload)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(DecodePayload)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(DecodePayload, payload)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x04, 0x00, 8,
+ 0x11, 0x22, 0x33, 0x44,
+ 0x55, 0x66, 0x77, 0x88
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+
+ // the caller has already parsed the T and L, so we point to just payload
+ ccnxCodecTlvDecoder_Advance(decoder, 4);
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodePayload(decoder, dictionary);
+ assertTrue(success, "Failed to decode a valid payload: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder)));
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 4, 12);
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(DecodePayload, payload_zero)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x04, 0x00, 0,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+
+ // the caller has already parsed the T and L, so we point to just payload
+ ccnxCodecTlvDecoder_Advance(decoder, 4);
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ bool success = ccnxCodecSchemaV1ValidationDecoder_DecodePayload(decoder, dictionary);
+ assertFalse(success, "Should have failed on 0-length payload");
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+// =========================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ValidationDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c
new file mode 100755
index 00000000..8a4d951a
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodecSchemaV1_ValidationEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h>
+
+#include "testrig_packetwrapper.c"
+
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+
+#include <ccnx/common/validation/ccnxValidation_CRC32C.h>
+#include <ccnx/common/validation/ccnxValidation_HmacSha256.h>
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ValidationDecoder)
+{
+ LONGBOW_RUN_TEST_FIXTURE(EncodeAlg);
+ LONGBOW_RUN_TEST_FIXTURE(EncodePayload);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ValidationDecoder)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ValidationDecoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(EncodeAlg)
+{
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, CRC32C);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, HMAC_SHA256);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, RSA_SHA256);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, DeduceFromSigner);
+
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeCertificate);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodePublicKey);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeKeyId);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeKeyName);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeSignatureTime_Specified);
+ LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeSignatureTime_Generated);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(EncodeAlg)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(EncodeAlg)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, CRC32C)
+{
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C;
+ PARCCryptoSuite suite = PARCCryptoSuite_NULL_CRC32C;
+
+ uint8_t encoded[] = {
+ 0x00, tlvSuite, 0x00, 0,
+ };
+
+ PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite);
+
+ ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary);
+ assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueEncoded, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&trueEncoded);
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, HMAC_SHA256)
+{
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256;
+ PARCCryptoSuite suite = PARCCryptoSuite_HMAC_SHA256;
+
+ uint8_t encoded[] = {
+ 0x00, tlvSuite, 0x00, 0,
+ };
+
+ PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite);
+
+ ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary);
+ assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueEncoded, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&trueEncoded);
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, RSA_SHA256)
+{
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256;
+ PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256;
+
+ uint8_t encoded[] = {
+ 0x00, tlvSuite, 0x00, 0,
+ };
+
+ PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite);
+
+ ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary);
+ assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueEncoded, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&trueEncoded);
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, DeduceFromSigner)
+{
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvsuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C;
+
+ uint8_t encoded[] = {
+ 0x00, tlvsuite, 0x00, 0,
+ };
+
+ PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+
+ ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary);
+ assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(trueEncoded, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&trueEncoded);
+ parcSigner_Release(&signer);
+}
+
+// =======
+
+LONGBOW_TEST_CASE(EncodeAlg, _encodeCertificate)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x0C, 0x00, 6,
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *cert = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxValidationFacadeV1_SetCertificate(dictionary, cert);
+
+ ssize_t length = _encodeCertificate(encoder, dictionary);
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&cert);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+
+LONGBOW_TEST_CASE(EncodeAlg, _encodePublicKey)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x0B, 0x00, 6,
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *key = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxValidationFacadeV1_SetPublicKey(dictionary, key);
+
+ ssize_t length = _encodePublicKey(encoder, dictionary);
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&key);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, _encodeKeyId)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x09, 0x00, 6,
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxValidationFacadeV1_SetKeyId(dictionary, keyid);
+
+ ssize_t length = _encodeKeyId(encoder, dictionary);
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&keyid);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, _encodeKeyName)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x0E, 0x00, 40,
+ // --- name
+ 0x00, 0x00, 0x00, 16,
+ 0x00, 0x03, 0x00, 5,
+ 'a', 'p', 'p', 'l',
+ 'e',
+ 0x00, 0x03, 0x00, 3,
+ 'p', 'i', 'e',
+ // --- keyid
+ 0x00, 0x01, 0x00, 4,
+ 0xa1, 0xa2, 0xa3, 0xa4,
+ // --- hash
+ 0x00, 0x02, 0x00, 8,
+ 0xb1, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8,
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 28, 32);
+ PARCBuffer *hash = parcBuffer_Wrap(encoded, sizeof(encoded), 36, 44);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/3=apple/3=pie");
+ CCNxLink *link = ccnxLink_Create(name, keyid, hash);
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxValidationFacadeV1_SetKeyName(dictionary, link);
+
+ ssize_t length = _encodeKeyName(encoder, dictionary);
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&keyid);
+ parcBuffer_Release(&hash);
+ ccnxName_Release(&name);
+ ccnxLink_Release(&link);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(EncodeAlg, _encodeSignatureTime_Specified)
+{
+ uint64_t sigtime = 0x1122334455667788ULL;
+ uint8_t encoded[] = {
+ 0x00, 0x0F, 0x00, 8,
+ 0x11, 0x22, 0x33, 0x44,
+ 0x55, 0x66, 0x77, 0x88
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxValidationFacadeV1_SetSigningTime(dictionary, sigtime);
+
+ ssize_t length = _encodeSignatureTime(encoder, dictionary);
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+/*
+ * Do not specify a signing time, but rather set a Signer and let the code
+ * create the time on its own
+ */
+LONGBOW_TEST_CASE(EncodeAlg, _encodeSignatureTime_Generated)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ PARCBuffer *password = parcBuffer_Wrap("password", 8, 0, 8);
+ PARCSigner *signer = ccnxValidationHmacSha256_CreateSigner(password);
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+ parcSigner_Release(&signer);
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+
+ ssize_t length = _encodeSignatureTime(encoder, dictionary);
+ assertTrue(length == 12, "Wrong length, expected 12, got %zd", length);
+
+ parcBuffer_Release(&password);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(EncodePayload)
+{
+ LONGBOW_RUN_TEST_CASE(EncodePayload, payload_Specified);
+ LONGBOW_RUN_TEST_CASE(EncodePayload, payload_Generated);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(EncodePayload)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(EncodePayload)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(EncodePayload, payload_Specified)
+{
+ uint8_t encoded[] = {
+ 0x11, 0x22, 0x33, 0x44,
+ 0x55, 0x66, 0x77, 0x88
+ };
+
+ PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxValidationFacadeV1_SetPayload(dictionary, truth);
+
+ ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodePayload(encoder, dictionary);
+ assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ parcBuffer_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+/*
+ * Put the guts of v1_interest_nameA_crc32c in to the encoding buffer and mark it
+ * as the signature block. Generate the CRC and make sure we got the right thing.
+ */
+LONGBOW_TEST_CASE(EncodePayload, payload_Generated)
+{
+ TlvExtent interestExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_INTEREST);
+
+ // This will test against the string (Interest, ValidationAlg, ValidationPayload)
+ PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c,
+ sizeof(v1_interest_nameA_crc32c),
+ interestExtent.offset,
+ sizeof(v1_interest_nameA_crc32c));
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+ parcSigner_Release(&signer);
+
+ // This will append from the beginning of the Interest message up to the end of the ValidationAlg
+ // This space is all marked as the "to-be-signed" section.
+ ccnxCodecTlvEncoder_MarkSignatureStart(encoder);
+ size_t signedInfoLenth = sizeof(v1_interest_nameA_crc32c) - 8 - interestExtent.offset;
+ ccnxCodecTlvEncoder_AppendRawArray(encoder, signedInfoLenth, v1_interest_nameA_crc32c + interestExtent.offset);
+ ccnxCodecTlvEncoder_MarkSignatureEnd(encoder);
+
+ // add the validation payload container, then generate the signature
+ ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_MessageType_ValidationPayload, 4);
+
+ // Do the actual encoding. This will calculate the signature on the fly.
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodePayload(encoder, dictionary);
+ assertTrue(length == 4, "Wrong length, expected 4 got %zd", length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ // Tests that we got the right signature (CRC32c in this case)
+ assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+}
+
+// =========================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ValidationDecoder);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c
new file mode 100644
index 00000000..f925dd28
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+#include <ccnx/common/codec/ccnxCodec_EncodingBuffer.h>
+
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h>
+
+
+#include <ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h>
+
+#include <ccnx/common/codec/test/testrig_Compare.c>
+
+/**
+ * Finds a row in the truthtable where bodyManifest is TRUE and the
+ * indexOrKey equals 'key'.
+ */
+TlvExtent
+getTruthTableExtent(TruthTableEntry *ttentry, int key)
+{
+ for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) {
+ if (ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) {
+ return ttentry[i].extent;
+ }
+ }
+ return (TlvExtent) { 0, 0 };
+}
+
+/**
+ * Finds a row in the truthtable where bodyManifest is FALSE and the
+ * indexOrKey equals 'key'.
+ */
+TlvExtent
+getTruthTableHeaderExtent(TruthTableEntry *ttentry, int key)
+{
+ for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) {
+ if (!ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) {
+ return ttentry[i].extent;
+ }
+ }
+ return (TlvExtent) { 0, 0 };
+}
+
+typedef struct test_data {
+ // the memory region extracted from a Truth Table entry
+ PARCBuffer *memoryRegion;
+
+ CCNxCodecTlvEncoder *encoder;
+ CCNxTlvDictionary *dictionary;
+
+ uint8_t *packet;
+ size_t packetLength;
+ TruthTableEntry *truthTable;
+
+ // If the user creates one of these, we'll destroy it.
+ PARCSigner *signer;
+} TestData;
+
+static SchemaV1ManifestContentObjectBody manifestContentObjectContainerArray[] = {
+ V1_MANIFEST_OBJ_CONTENTOBJECT,
+ V1_MANIFEST_OBJ_NAMEAUTH,
+ V1_MANIFEST_OBJ_ValidationPayload,
+ V1_MANIFEST_OBJ_KEYNAME,
+ V1_MANIFEST_OBJ_METADATA,
+ V1_MANIFEST_OBJ_ValidationAlg,
+ V1_MANIFEST_OBJ_BODYEND
+};
+
+static bool
+isContentObjectContainer(SchemaV1ManifestContentObjectBody value)
+{
+ for (int i = 0; manifestContentObjectContainerArray[i] != V1_MANIFEST_OBJ_BODYEND; i++) {
+ if (value == manifestContentObjectContainerArray[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * The testdata truth tables were written with the tlv_1.0 array indicies, so we
+ * need to translate those old indicies to the new indicies.
+ */
+static CCNxCodecSchemaV1TlvDictionary_MessageFastArray
+translateTestDataManifestToSchemaKey(SchemaV1ManifestContentObjectBody oldKey)
+{
+ switch (oldKey) {
+ case V1_MANIFEST_INT_NAME:
+ // fallthrough
+ case V1_MANIFEST_OBJ_NAME:
+ return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME;
+
+ case V1_MANIFEST_OBJ_PAYLOAD:
+ return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD;
+
+ case V1_MANIFEST_OBJ_KEYID:
+ return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID;
+
+ case V1_MANIFEST_OBJ_CRYPTO_SUITE:
+ return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE;
+
+ case V1_MANIFEST_OBJ_KEY:
+ return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY;
+
+ case V1_MANIFEST_OBJ_CERT:
+ return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT;
+
+ case V1_MANIFEST_OBJ_KEYNAME_NAME:
+ return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME;
+
+ case V1_MANIFEST_OBJ_KEYNAME_OBJHASH:
+ return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH;
+
+ case V1_MANIFEST_OBJ_OBJ_TYPE:
+ return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE;
+
+ case V1_MANIFEST_OBJ_SIGBITS:
+ return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD;
+
+ case V1_MANIFEST_OBJ_SigningTime:
+ return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME;
+
+ case V1_MANIFEST_OBJ_ENDSEGMENT:
+ return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT;
+
+ case V1_MANIFEST_INT_KEYID:
+ return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION;
+
+ case V1_MANIFEST_INT_OBJHASH:
+ return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION;
+
+ default:
+ trapIllegalValue(oldKey, "Unexpected old manifest value: %d", oldKey);
+ break;
+ }
+ return -1;
+}
+
+/**
+ * The testdata truth tables were written with the tlv_1.0 array indicies, so we
+ * need to translate those old indicies to the new indicies.
+ */
+static CCNxCodecSchemaV1TlvDictionary_HeadersFastArray
+translateOldOptionalHeadersManifestToNewKey(CCNxTlvDictionary *packetDictionary, int oldKey)
+{
+ if (ccnxTlvDictionary_IsInterest(packetDictionary)) {
+ switch (oldKey) {
+ case V1_MANIFEST_INT_LIFETIME:
+ return CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime;
+
+ case V1_MANIFEST_INT_E2EFRAG:
+ return CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG;
+
+ default:
+ trapIllegalValue(oldKey, "Unexpected old manifest value: %d", oldKey);
+ break;
+ }
+ } else if (ccnxTlvDictionary_IsContentObject(packetDictionary)) {
+ switch (oldKey) {
+ case V1_MANIFEST_OBJ_E2EFRAG:
+ return CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG;
+
+ default:
+ trapIllegalValue(oldKey, "Unexpected old manifest value: %d", oldKey);
+ break;
+ }
+ }
+ return -1;
+}
+
+static void
+addBuffer(TestData *data, CCNxTlvDictionary *packetDictionary, size_t item_start, size_t item_end, uint32_t translatedKey)
+{
+ PARCBuffer *itemBuffer = parcBuffer_Wrap(data->packet, data->packetLength, item_start, item_end);
+ ccnxTlvDictionary_PutBuffer(packetDictionary, translatedKey, itemBuffer);
+ parcBuffer_Release(&itemBuffer);
+}
+
+/**
+ * The extent should be treated like a CCNxName, so decode it and add it as a CCNxName.
+ */
+static void
+addName(TestData *data, CCNxTlvDictionary *packetDictionary, size_t item_start, size_t item_end, uint32_t translatedKey)
+{
+ // we need to backup 4 bytes to the the TLV container
+ PARCBuffer *itemBuffer = parcBuffer_Wrap(data->packet, data->packetLength, item_start - 4, item_end);
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(itemBuffer);
+ CCNxName *name = ccnxCodecSchemaV1NameCodec_Decode(decoder, CCNxCodecSchemaV1Types_CCNxMessage_Name);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+
+ ccnxTlvDictionary_PutName(packetDictionary, translatedKey, name);
+ ccnxName_Release(&name);
+ parcBuffer_Release(&itemBuffer);
+}
+
+
+/**
+ * Called on the body of a content object, does not include the fixed header or optional headers
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+buildContentObjectDictionary(TestData *data, CCNxTlvDictionary *packetDictionary, TlvExtent extent)
+{
+ size_t start = extent.offset;
+ size_t end = start + extent.length;
+
+ ccnxTlvDictionary_SetMessageType_ContentObject(packetDictionary, CCNxTlvDictionary_SchemaVersion_V1);
+
+ for (int i = 0; data->truthTable[i].indexOrKey != T_INVALID; i++) {
+ size_t item_start = data->truthTable[i].extent.offset;
+ size_t item_end = item_start + data->truthTable[i].extent.length;
+
+ // Is this item included in the given extent?
+ if (start < item_start && item_end <= end) {
+ // Is it a container or a nested dictionary? This check only applies to a ContentObject
+ if (!isContentObjectContainer(data->truthTable[i].indexOrKey)) {
+ uint32_t translatedKey = translateTestDataManifestToSchemaKey(data->truthTable[i].indexOrKey);
+
+ if (data->truthTable[i].indexOrKey == V1_MANIFEST_OBJ_NAME) {
+ addName(data, packetDictionary, item_start, item_end, translatedKey);
+ } else {
+ addBuffer(data, packetDictionary, item_start, item_end, translatedKey);
+ }
+ }
+ }
+ }
+}
+
+static void
+buildInterestDictionary(TestData *data, CCNxTlvDictionary *packetDictionary, TlvExtent extent)
+{
+ size_t start = extent.offset;
+ size_t end = start + extent.length;
+
+ ccnxTlvDictionary_SetMessageType_Interest(packetDictionary, CCNxTlvDictionary_SchemaVersion_V1);
+
+ for (int i = 0; data->truthTable[i].indexOrKey != T_INVALID && data->truthTable[i].bodyManifest; i++) {
+ size_t item_start = data->truthTable[i].extent.offset;
+ size_t item_end = item_start + data->truthTable[i].extent.length;
+
+ // Is this item included in the given extent?
+ if (start < item_start && item_end <= end) {
+ uint32_t translatedKey = translateTestDataManifestToSchemaKey(data->truthTable[i].indexOrKey);
+
+ if (data->truthTable[i].indexOrKey == V1_MANIFEST_INT_NAME) {
+ addName(data, packetDictionary, item_start, item_end, translatedKey);
+ } else {
+ addBuffer(data, packetDictionary, item_start, item_end, translatedKey);
+ }
+ }
+ }
+}
+
+/**
+ * Make a dictionary entry for everything inside the selected extent, not including it
+ *
+ * Use the truth table and for each listed item whose extent is within the given extent,
+ * add a dictionary entry
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+buildMessageDictionary(TestData *data, CCNxTlvDictionary *dictionary, TlvExtent extent)
+{
+ uint8_t packetType = data->packet[1];
+ switch (packetType) {
+ case CCNxCodecSchemaV1Types_PacketType_Interest:
+ buildInterestDictionary(data, dictionary, extent);
+ break;
+
+ case CCNxCodecSchemaV1Types_PacketType_ContentObject:
+ buildContentObjectDictionary(data, dictionary, extent);
+ break;
+
+ case CCNxCodecSchemaV1Types_PacketType_InterestReturn:
+ trapNotImplemented("not implemented");
+ break;
+
+ default:
+ trapIllegalValue(packetType, "Unknown PacketType");
+ }
+}
+
+static void
+buildSetDictionaryType(TestData *data, CCNxTlvDictionary *dictionary)
+{
+ uint8_t packetType = data->packet[1];
+ switch (packetType) {
+ case CCNxCodecSchemaV1Types_PacketType_Interest:
+ ccnxTlvDictionary_SetMessageType_Interest(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ break;
+
+ case CCNxCodecSchemaV1Types_PacketType_ContentObject:
+ ccnxTlvDictionary_SetMessageType_ContentObject(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ break;
+
+ case CCNxCodecSchemaV1Types_PacketType_InterestReturn:
+ trapNotImplemented("not implemented");
+ break;
+
+ default:
+ trapIllegalValue(packetType, "Unknown PacketType");
+ }
+}
+
+/**
+ * Builds a packet dictionary with OptionalHeaders and Message
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+buildPacketDictionary(TestData *data, CCNxTlvDictionary *packetDictionary, TlvExtent extent)
+{
+ buildSetDictionaryType(data, packetDictionary);
+
+ size_t start = extent.offset;
+ size_t end = start + extent.length;
+
+ for (int i = 0; data->truthTable[i].indexOrKey != T_INVALID; i++) {
+ size_t item_start = data->truthTable[i].extent.offset;
+ size_t item_end = item_start + data->truthTable[i].extent.length;
+
+ // Is this item included in the given extent?
+ if (start < item_start && item_end <= end) {
+ if (data->truthTable[i].bodyManifest == false) {
+ PARCBuffer *itemBuffer = parcBuffer_Wrap(data->packet, data->packetLength, item_start, item_end);
+ uint32_t translatedKey = translateOldOptionalHeadersManifestToNewKey(packetDictionary, data->truthTable[i].indexOrKey);
+ ccnxTlvDictionary_PutBuffer(packetDictionary, translatedKey, itemBuffer);
+ parcBuffer_Release(&itemBuffer);
+ } else {
+ buildMessageDictionary(data, packetDictionary, data->truthTable[i].extent);
+ }
+
+ // advance start to skip over whatever we just included
+ start = item_end;
+ }
+ }
+}
+
+/**
+ * Wraps the given (packet, length) in a PARCBuffer where the data->memoryRegion member will be set
+ * to a given extent within that PARCBuffer. The function will locate the truthTableKey in the truthTable and
+ * use it's extent as the bounds for the wrapped packet.
+ *
+ * For example, if the key V1_INT_NAME has the extent {32, 12}, then the PARCBuffer will wrap the packet
+ * memory and it will have and offset of 32 and a limit of 12.
+ */
+TestData *
+commonSetup(uint8_t *packet, size_t length, TruthTableEntry *truthTable, int truthTableKey)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ TlvExtent extent = getTruthTableExtent(truthTable, truthTableKey);
+
+ data->memoryRegion = parcBuffer_Wrap(packet, length, extent.offset, extent.offset + extent.length);
+ data->encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(data->encoder);
+
+ // use the content object lenghts, they are the largest
+ data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+
+ data->packet = packet;
+ data->packetLength = length;
+ data->truthTable = truthTable;
+
+ buildMessageDictionary(data, data->dictionary, extent);
+ return data;
+}
+
+/**
+ * Wraps a packet like commonSetup, but will do the whole packet including headers not just
+ * the message body. This is used by the PacketEncoder tests.
+ */
+TestData *
+testrigencoder_CommonSetupWholePacket(uint8_t *packet, size_t length, TruthTableEntry *truthTable)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->memoryRegion = parcBuffer_Wrap(packet, length, 0, length);
+ data->encoder = ccnxCodecTlvEncoder_Create();
+
+ // use the content object lenghts, they are the largest
+ data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+
+ data->packet = packet;
+ data->packetLength = length;
+ data->truthTable = truthTable;
+
+ buildPacketDictionary(data, data->dictionary, (TlvExtent) { 0, length });
+
+ return data;
+}
+
+void
+testrigencoder_CommonTeardown(TestData *data)
+{
+ ccnxTlvDictionary_Release(&data->dictionary);
+ ccnxCodecTlvEncoder_Destroy(&data->encoder);
+ parcBuffer_Release(&data->memoryRegion);
+
+ if (data->signer) {
+ parcSigner_Release(&data->signer);
+ }
+
+ parcMemory_Deallocate((void **) &data);
+}
+
+void
+testDisplayIoVec(CCNxCodecEncodingBufferIOVec *vec)
+{
+ printf("Display iovec %p with %d elements\n", (void *) vec, vec->iovcnt);
+ size_t totalLength = 0;
+ for (int i = 0; i < vec->iovcnt; i++) {
+ totalLength += vec->iov[i].iov_len;
+ printf(" %3d: base %p length %4zu total length %4zu\n", i, (void *) vec->iov[i].iov_base, vec->iov[i].iov_len, totalLength);
+ }
+ printf("done\n\n");
+}
+
+void
+testExecute(TestData *data, ssize_t (*encoderFunction)(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *dictionary))
+{
+ encoderFunction(data->encoder, data->dictionary);
+ testCompareEncoderToBuffer(data->encoder, data->memoryRegion);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c
new file mode 100644
index 00000000..9a213b13
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This test rig sets up test data to wrap a packet and prepare it for use in a decoder
+ *
+ * A hand-encoded packet, such as from the testdata directory can be passed to commonSetup and then
+ * run automated tests against it based on its manifest.
+ *
+ * Example:
+ * @code
+ *
+ * static uint8_t object_nameC_keyid3_protoinfo[] = {
+ * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110
+ * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5
+ * // ---------------------------
+ * // snip middle of packet
+ * // ------------------------
+ * // byte offset 76
+ * 0x00, 0x03, 0x00, 26, // Protocol Information, length = 26
+ * 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17
+ * 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1
+ * 0x04, // LINK
+ * 0x00, 0x0D, 0x00, 8, // Creation Time
+ * 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec
+ * 0x4B, 0x19, 0x84, 0x00,
+ * 0x00, 0x19, 0x00, 0x01, // EndSegment, length = 1
+ * 42,
+ * // ---------------------------
+ * // snip to end of packet
+ * // ---------------------------
+ * };
+ *
+ * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = {
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_METADATA, .bodyManifest=true, .extent = { 80, 17} },
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_OBJ_TYPE, .bodyManifest=true, .extent = { 84, 1} },
+ * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} },
+ * };
+ *
+ * LONGBOW_TEST_FIXTURE_SETUP(Global)
+ * {
+ * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_METADATA);
+ * return LONGBOW_STATUS_SUCCEEDED;
+ * }
+ *
+ * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber)
+ * {
+ * testInt32Getter(testCase, MANIFEST_OBJ_OBJ_TYPE, ccnxCodecSchemaV0Metadata_Decode, ccnxCodecSchemaV0Metadata_GetContentType);
+ * }
+ *
+ * @endcode
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvUtilities.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h>
+
+/**
+ * Finds a row in the truthtable where bodyManifest is TRUE and the
+ * indexOrKey equals 'key'.
+ */
+TlvExtent
+getTruthTableExtent(TruthTableEntry *ttentry, int key)
+{
+ for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) {
+ if (ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) {
+ return ttentry[i].extent;
+ }
+ }
+ return (TlvExtent) { 0, 0 };
+}
+
+/**
+ * Finds a row in the truthtable where bodyManifest is FALSE and the
+ * indexOrKey equals 'key'.
+ */
+TlvExtent
+getTruthTableHeaderExtent(TruthTableEntry *ttentry, int key)
+{
+ for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) {
+ if (!ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) {
+ return ttentry[i].extent;
+ }
+ }
+ return (TlvExtent) { 0, 0 };
+}
+
+typedef struct test_data {
+ PARCBuffer *interest;
+ CCNxCodecTlvDecoder *decoder;
+ CCNxTlvDictionary *dictionary;
+
+ uint8_t *packet;
+ size_t packetLength;
+ TruthTableEntry *truthTable;
+} TestData;
+
+/**
+ * Wraps the given (packet, length) in a PARCBuffer where the data->memoryRegion member will be set
+ * to a given extent within that PARCBuffer. The function will locate the truthTableKey in the truthTable and
+ * use it's extent as the bounds for the wrapped packet.
+ *
+ * For example, if the key V1_INT_NAME has the extent {32, 12}, then the PARCBuffer will wrap the packet
+ * memory and it will have and offset of 32, position 0, and a limit of 12.
+ */
+TestData *
+commonSetup(uint8_t *packet, size_t length, TruthTableEntry *truthTable, int truthTableKey)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ TlvExtent extent = getTruthTableExtent(truthTable, truthTableKey);
+
+ data->interest = parcBuffer_Wrap(packet, length, extent.offset, extent.offset + extent.length);
+ data->decoder = ccnxCodecTlvDecoder_Create(data->interest);
+
+ // content objects have more fields than interests, so use that
+ data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+
+ data->packet = packet;
+ data->packetLength = length;
+ data->truthTable = truthTable;
+ return data;
+}
+
+void
+commonSetupWholePacket(LongBowTestCase *testCase, uint8_t *packet, size_t length, TruthTableEntry *truthTable)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->interest = parcBuffer_Wrap(packet, length, 0, length);
+ data->decoder = ccnxCodecTlvDecoder_Create(data->interest);
+ data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+
+ data->packet = packet;
+ data->packetLength = length;
+ data->truthTable = truthTable;
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+}
+
+void
+commonTeardown(TestData *data)
+{
+ ccnxTlvDictionary_Release(&data->dictionary);
+ ccnxCodecTlvDecoder_Destroy(&data->decoder);
+ parcBuffer_Release(&data->interest);
+ parcMemory_Deallocate((void **) &data);
+}
+
+/**
+ * Tests that an int32_t getter returns the right value
+ *
+ * Given a packet byte array and a truth table (see transport/test_tools/testdata/testrig_truthTable.h),
+ * check that the buffer the decoder parsed is the right buffer.
+ *
+ * The function will run the specified decoder on the TestData's packet and put the results in the
+ * TestData's dictionary. It will then call the specified getter and make sure its value is equal
+ * to the truth table's value.
+ *
+ * The function will assert if the test fails.
+ *
+ * @param [in] testCase Used to get the clipboard data with the TestData member
+ * @param [in] truthTableKey Used to match the .indexOrKey truth table member
+ * @param [in] containerDecoder The decoder to use on the packet contained in TestData
+ * @param [in] getter The function to call to fetch a decoded value
+ *
+ * Example:
+ * @code
+ *
+ * static uint8_t object_nameC_keyid3_protoinfo[] = {
+ * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110
+ * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5
+ * // ---------------------------
+ * // snip middle of packet
+ * // ------------------------
+ * // byte offset 76
+ * 0x00, 0x03, 0x00, 26, // Protocol Information, length = 26
+ * 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17
+ * 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1
+ * 0x04, // LINK
+ * 0x00, 0x0D, 0x00, 8, // Creation Time
+ * 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec
+ * 0x4B, 0x19, 0x84, 0x00,
+ * 0x00, 0x19, 0x00, 0x01, // EndSegment, length = 1
+ * 42,
+ * // ---------------------------
+ * // snip to end of packet
+ * // ---------------------------
+ * };
+ *
+ * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = {
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_METADATA, .bodyManifest=true, .extent = { 80, 17} },
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_OBJ_TYPE, .bodyManifest=true, .extent = { 84, 1} },
+ * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} },
+ * };
+ *
+ * LONGBOW_TEST_FIXTURE_SETUP(Global)
+ * {
+ * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_METADATA);
+ * return LONGBOW_STATUS_SUCCEEDED;
+ * }
+ *
+ * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber)
+ * {
+ * testInt32Getter(testCase, MANIFEST_OBJ_OBJ_TYPE, ccnxCodecSchemaV0Metadata_Decode, ccnxCodecSchemaV0Metadata_GetContentType);
+ * }
+ * * @endcode
+ */
+void
+testInt32Getter(LongBowTestCase *testCase, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *),
+ int32_t (*getter)(CCNxTlvDictionary *))
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ containerDecoder(data->decoder, data->dictionary);
+ int32_t testvalue = getter(data->dictionary);
+
+ // look up the true name buffer from the truth table
+ TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey);
+ PARCBuffer *truthbuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length);
+ uint64_t truthvalue = -2;
+ ccnxCodecTlvUtilities_GetVarInt(truthbuffer, parcBuffer_Remaining(truthbuffer), &truthvalue);
+
+ parcBuffer_Release(&truthbuffer);
+
+ assertTrue(testvalue == (int32_t) truthvalue, "Wrong value, got %d expected %d", testvalue, (int32_t) truthvalue);
+}
+
+/**
+ * Tests that an int64_t getter returns the right value
+ *
+ * Given a packet byte array and a truth table (see transport/test_tools/testdata/testrig_truthTable.h),
+ * check that the buffer the decoder parsed is the right buffer.
+ *
+ * The function will run the specified decoder on the TestData's packet and put the results in the
+ * TestData's dictionary. It will then call the specified getter and make sure its value is equal
+ * to the truth table's value.
+ *
+ * The function will assert if the test fails.
+ *
+ * @param [in] testCase Used to get the clipboard data with the TestData member
+ * @param [in] truthTableKey Used to match the .indexOrKey truth table member
+ * @param [in] containerDecoder The decoder to use on the packet contained in TestData
+ * @param [in] getter The function to call to fetch a decoded value
+ *
+ * Example:
+ * @code
+ *
+ * static uint8_t object_nameC_keyid3_protoinfo[] = {
+ * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110
+ * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5
+ * // ---------------------------
+ * // snip middle of packet
+ * // ------------------------
+ * // byte offset 76
+ * 0x00, 0x03, 0x00, 26, // Protocol Information, length = 26
+ * 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17
+ * 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1
+ * 0x04, // LINK
+ * 0x00, 0x0D, 0x00, 8, // Creation Time
+ * 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec
+ * 0x4B, 0x19, 0x84, 0x00,
+ * 0x00, 0x19, 0x00, 0x01, // EndSegment, length = 1
+ * 42,
+ * // ---------------------------
+ * // snip to end of packet
+ * // ---------------------------
+ * };
+ *
+ * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = {
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_PROTOINFO, .bodyManifest=true, .extent = { 76, 26} },
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_ENDSEGMENT, .bodyManifest=true, .extent = {101, 1} },
+ * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} },
+ * };
+ *
+ * LONGBOW_TEST_FIXTURE_SETUP(Global)
+ * {
+ * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_PROTOINFO);
+ * return LONGBOW_STATUS_SUCCEEDED;
+ * }
+ *
+ * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber)
+ * {
+ * testInt64Getter(testCase, MANIFEST_OBJ_ENDSEGMENT, ccnxCodecSchemaV0ProtoInfo_Decode, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber);
+ * }
+ *
+ * @endcode
+ */
+void
+testInt64Getter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *),
+ int64_t (*getter)(CCNxTlvDictionary *))
+{
+ containerDecoder(data->decoder, data->dictionary);
+ int64_t testvalue = getter(data->dictionary);
+
+ // look up the true name buffer from the truth table
+ TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey);
+ PARCBuffer *truthbuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length);
+ uint64_t truthvalue = -2;
+ ccnxCodecTlvUtilities_GetVarInt(truthbuffer, parcBuffer_Remaining(truthbuffer), &truthvalue);
+
+ parcBuffer_Release(&truthbuffer);
+
+ assertTrue(testvalue == (int64_t) truthvalue, "Wrong value, got %" PRId64 " expected %" PRId64, testvalue, (int64_t) truthvalue);
+}
+
+/**
+ * Tests that a buffer getter returns the right buffer
+ *
+ * Given a packet byte array and a truth table (see transport/test_tools/testdata/testrig_truthTable.h),
+ * check that the buffer the decoder parsed is the right buffer.
+ *
+ * The function will run the specified decoder on the TestData's packet and put the results in the
+ * TestData's dictionary. It will then call the specified getter and make sure its value is equal
+ * to the truth table's value.
+ *
+ * The function will assert if the test fails.
+ *
+ * @param [in] testCase Used to get the clipboard data with the TestData member
+ * @param [in] truthTableKey Used to match the .indexOrKey truth table member
+ * @param [in] containerDecoder The decoder to use on the packet contained in TestData
+ * @param [in] getter The function to call to fetch a decoded value
+ *
+ * Example:
+ * @code
+ *
+ * static uint8_t object_nameC_keyid3_protoinfo[] = {
+ * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110
+ * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5
+ * // ---------------------------
+ * // snip middle of packet
+ * // ------------------------
+ * // byte offset = 117
+ * 0x00, 0x05, 0x00, 0x06, // signature block, length = 6
+ * 0x00, 0x0E, 0x00, 0x02, // signature bits, length = 2
+ * 0xBE, 0xEF // value = 0xBEEF
+ * };
+ *
+ * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = {
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_SIGBLOCK, .bodyManifest=true, .extent = {117, 6} },
+ * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_SIGBITS, .bodyManifest=true, .extent = {121, 2} },
+ * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} },
+ * };
+ *
+ * LONGBOW_TEST_FIXTURE_SETUP(Global)
+ * {
+ * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_SIGBLOCK);
+ * return LONGBOW_STATUS_SUCCEEDED;
+ * }
+ *
+ * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0SigBlock_GetSignatureBits)
+ * {
+ * testBufferGetter(testCase, MANIFEST_OBJ_SIGBITS, ccnxCodecSchemaV0SigBlock_Decode, ccnxCodecSchemaV0SigBlock_GetSignatureBits);
+ * }
+ *
+ * @endcode
+ */
+void
+testBufferGetter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *),
+ PARCBuffer *(*getter)(const CCNxTlvDictionary *))
+{
+ containerDecoder(data->decoder, data->dictionary);
+ PARCBuffer *test = getter(data->dictionary);
+
+ // look up the true name buffer from the truth table
+ TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey);
+ PARCBuffer *truth = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length);
+
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers not equal")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got:\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truth);
+}
+
+void
+testHashGetter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *),
+ PARCCryptoHash *(*getter)(CCNxTlvDictionary *))
+{
+ containerDecoder(data->decoder, data->dictionary);
+ PARCCryptoHash *testHash = getter(data->dictionary);
+
+ // look up the true hash buffer from the truth table
+ TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey);
+ PARCBuffer *truthBuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length);
+
+ // decode the hash value
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(truthBuffer);
+ PARCCryptoHash *truthHash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, extent.length);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+
+ // compare the decoded value against the expected value
+ assertTrue(parcCryptoHash_Equals(testHash, truthHash), "Hashes not equal")
+ {
+ printf("Expected:\n");
+ printf(" %s\n", parcBuffer_ToHexString(parcCryptoHash_GetDigest(truthHash)));
+ printf("Got:\n");
+ printf(" %s\n", parcBuffer_ToHexString(parcCryptoHash_GetDigest(testHash)));
+ }
+
+ parcCryptoHash_Release(&truthHash);
+ parcBuffer_Release(&truthBuffer);
+}
+
+void
+testNameGetter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *),
+ CCNxName *(*getter)(CCNxTlvDictionary *))
+{
+ containerDecoder(data->decoder, data->dictionary);
+ CCNxName *test = getter(data->dictionary);
+
+ // look up the true name buffer from the truth table
+ TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey);
+
+ // we need to backup 4 bytes to get the TLV container
+ PARCBuffer *truthBuffer =
+ parcBuffer_Wrap(data->packet, data->packetLength, extent.offset - 4, extent.offset + extent.length);
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(truthBuffer);
+ CCNxName *truthName = ccnxCodecSchemaV1NameCodec_Decode(decoder, CCNxCodecSchemaV1Types_CCNxMessage_Name);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+
+ assertTrue(ccnxName_Equals(test, truthName), "Names not equal")
+ {
+ printf("Expected:\n");
+ ccnxName_Display(truthName, 3);
+ printf("Got:\n");
+ ccnxName_Display(test, 3);
+ }
+
+ ccnxName_Release(&truthName);
+ parcBuffer_Release(&truthBuffer);
+}
+
+void
+testMissingInt32Getter(LongBowTestCase *testCase, int32_t (*getter)(CCNxTlvDictionary *))
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int32_t test = getter(data->dictionary);
+
+ assertTrue(test == -1, "Wrong value, got %d expected %d", test, -1);
+}
+
+/**
+ * Tried to retrieve execute the getter on the dictionary and ensures that
+ * the field is missing.
+ */
+void
+testMissingInt64Getter(LongBowTestCase *testCase, int64_t (*getter)(CCNxTlvDictionary *))
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int64_t test = getter(data->dictionary);
+
+ assertTrue(test == -1, "Wrong value, got %" PRId64 " expected %d", test, -1);
+}
+
+/**
+ * Tried to retrieve execute the getter on the dictionary and ensures that
+ * the field is missing.
+ */
+void
+testMissingNameGetter(LongBowTestCase *testCase, CCNxName *(*getter)(CCNxTlvDictionary *))
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxName *test = getter(data->dictionary);
+
+ assertNull(test, "Should have gotten null for missing field, got %p", (void *) test);
+}
+
+/**
+ * Tried to retrieve execute the getter on the dictionary and ensures that
+ * the field is missing.
+ */
+void
+testMissingBufferGetter(LongBowTestCase *testCase, PARCBuffer *(*getter)(CCNxTlvDictionary *))
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *test = getter(data->dictionary);
+
+ assertNull(test, "Should have gotten null for missing field, got %p", (void *) test);
+}
+
+/**
+ * Tried to retrieve execute the getter on the dictionary and ensures that
+ * the field is missing.
+ */
+void
+testMissingDictionaryGetter(LongBowTestCase *testCase, CCNxTlvDictionary *(*getter)(CCNxTlvDictionary *))
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *test = getter(data->dictionary);
+
+ assertNull(test, "Should have gotten null for missing field, got %p", (void *) test);
+}
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/CMakeLists.txt b/libccnx-common/ccnx/common/codec/schema_v1/testdata/CMakeLists.txt
new file mode 100644
index 00000000..c5c70ce4
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/CMakeLists.txt
@@ -0,0 +1,27 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_ccnxCodecSchemaV1_CryptoSuite
+ test_ccnxCodecSchemaV1_FixedHeaderDecoder
+ test_ccnxCodecSchemaV1_FixedHeaderEncoder
+ test_ccnxCodecSchemaV1_LinkCodec
+ test_ccnxCodecSchemaV1_MessageDecoder
+ test_ccnxCodecSchemaV1_MessageEncoder
+ test_ccnxCodecSchemaV1_NameCodec
+ test_ccnxCodecSchemaV1_NameSegmentCodec
+ test_ccnxCodecSchemaV1_OptionalHeadersDecoder
+ test_ccnxCodecSchemaV1_OptionalHeadersEncoder
+ test_ccnxCodecSchemaV1_PacketDecoder
+ test_ccnxCodecSchemaV1_PacketEncoder
+ test_ccnxCodecSchemaV1_TlvDictionary
+ test_ccnxCodecSchemaV1_ValidationDecoder
+ test_ccnxCodecSchemaV1_ValidationEncoder
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h
new file mode 100644
index 00000000..70899d13
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Defines the truthtable manifest constants used by the version 1 test vectors.
+ *
+ */
+
+/**
+ * Schema for Control Plane Interface packets. These packets are a TLV wrapping
+ * the control JSON.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+#ifndef Libccnx_v1_CPISchema_h
+#define Libccnx_v1_CPISchema_h
+
+#include <ccnx/common/codec/testdata/tlv_Schema.h>
+
+// -----------------------------------------------------
+// these are the array indicies used to store the TlvExtent for the item
+typedef enum {
+ V1_MANIFEST_CPI_PAYLOAD = 0,
+ V1_MANIFEST_CPI_SIGBITS = 5, // the payload of the signature
+ V1_MANIFEST_CPI_ValidationAlg = 6, // start of validation algorithm
+ V1_MANIFEST_CPI_ValidationPayload = 7, // start of validation payload
+ V1_MANIFEST_CPI_BODYEND = 8
+} V1_ManifestCPIBody;
+
+typedef enum {
+ V1_MANIFEST_CPI_HEADEND = 0
+} V1_ManifestCPIHeaders;
+
+#endif // Libccnx_tlv_CPISchema_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h
new file mode 100644
index 00000000..cb59d937
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This is from the version 1 codec. All the test vectors in this directory (e.g. interest_nameA.h)
+ * are encoded using these constants. These are no longer used for any functional code, only to interpret the test vectors.
+ *
+ */
+
+#ifndef Libccnx_v1_ContentObjectSchema_h
+#define Libccnx_v1_ContentObjectSchema_h
+
+#include <ccnx/common/codec/testdata/tlv_Schema.h>
+
+#define T_CONTENTOBJECT 0x0002
+
+// these are the array indicies used to store the TlvExtent for the item
+typedef enum {
+ // top level entities
+ V1_MANIFEST_OBJ_NAME = 0,
+ V1_MANIFEST_OBJ_CONTENTOBJECT = 1, // the top container
+ V1_MANIFEST_OBJ_NAMEAUTH = 2,
+ V1_MANIFEST_OBJ_PAYLOADTYPE = 3,
+ V1_MANIFEST_OBJ_PAYLOAD = 4,
+ V1_MANIFEST_OBJ_SIGBITS = 5,
+
+ // inside the name authenticator
+ V1_MANIFEST_OBJ_KEYID = 6,
+ V1_MANIFEST_OBJ_CRYPTO_SUITE = 7,
+ V1_MANIFEST_OBJ_KEY = 8,
+ V1_MANIFEST_OBJ_CERT = 9,
+ V1_MANIFEST_OBJ_KEYNAME = 10,
+ V1_MANIFEST_OBJ_KEYNAME_NAME = 11,
+ V1_MANIFEST_OBJ_KEYNAME_OBJHASH = 12,
+
+ // inside the protocol information
+ V1_MANIFEST_OBJ_METADATA = 13,
+
+ // inside metadata
+ V1_MANIFEST_OBJ_OBJ_TYPE = 14,
+ V1_MANIFEST_OBJ_CREATE_TIME = 15,
+ V1_MANIFEST_OBJ_EXPIRY_TIME = 16,
+
+ // inside signature block
+ V1_MANIFEST_OBJ_ValidationPayload = 17,
+ V1_MANIFEST_OBJ_ENDSEGMENT = 18,
+ V1_MANIFEST_OBJ_PUBKEY = 19,
+
+ V1_MANIFEST_OBJ_ValidationAlg = 20,
+ V1_MANIFEST_OBJ_SigningTime = 21,
+ V1_MANIFEST_OBJ_BODYEND = 22
+} SchemaV1ManifestContentObjectBody;
+
+typedef enum {
+ V1_MANIFEST_OBJ_OPTHEAD = 0,
+ V1_MANIFEST_OBJ_E2EFRAG = 2,
+ V1_MANIFEST_OBJ_FIXEDHEADER = 3,
+ V1_MANIFEST_OBJ_RecommendedCacheTime = 4,
+ V1_MANIFEST_OBJ_HEADEND = 5
+} SchemaV1ManifestContentObjectHeaders;
+
+#endif // Libccnx_tlv_ContentObjectSchema_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h
new file mode 100644
index 00000000..894b3cc7
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This is from the version 0 codec. All the test vectors in this directory (e.g. interest_nameA.h)
+ * are encoded using these constants. These are no longer used for any functional code, only to interpret the test vectors.
+ *
+ */
+
+#ifndef Libccnx_v1_InterestSchema_h
+#define Libccnx_v1_InterestSchema_h
+
+#include <ccnx/common/codec/testdata/tlv_Schema.h>
+
+// -----------------------------------------------------
+// these are the array indicies used to store the TlvExtent for the item
+typedef enum {
+ V1_MANIFEST_INT_INTEREST = 0, // start of Interest body to end
+
+ V1_MANIFEST_INT_NAME = 1,
+ V1_MANIFEST_INT_KEYID = 2,
+ V1_MANIFEST_INT_OBJHASH = 3,
+ V1_MANIFEST_INT_PAYLOAD = 4,
+ V1_MANIFEST_INT_IPIDM = 5,
+
+ V1_MANIFEST_INT_ValidationAlg = 6, // start of validation algorithm
+ V1_MANIFEST_INT_ValidationPayload = 7, // start of validation payload
+
+ V1_MANIFEST_INT_BODYEND = 7
+} ScheamV1ManifestInterestBody;
+
+typedef enum {
+ V1_MANIFEST_INT_OPTHEAD = 0, // the start of the optional headers
+ V1_MANIFEST_INT_LIFETIME = 1,
+ V1_MANIFEST_INT_E2EFRAG = 2,
+ V1_MANIFEST_INT_HEADEND = 3,
+} ScheamV1ManifestInterestHeaders;
+
+
+#define T_INTEREST 0x0001
+
+#endif // Libccnx_tlv_InterestSchema_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h
new file mode 100644
index 00000000..e4695849
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file interest_nameA_crc32c.h
+ * @brief Interest with CRC validation
+ *
+ * Ground truth set derived from CRC RevEng http://reveng.sourceforge.net
+ * e.g. reveng -c -m CRC-32C 313233343536373839 gives the canonical check value 0xe306928e
+ *
+ * You can also calcaulate CRC32C online at http://www.zorc.breitbandkatze.de/crc.html using
+ * CRC polynomial 0x1EDC6F41, init 0xFFFFFFFF, final 0xFFFFFFFF, reverse data bytes (check),
+ * and reverse CRC result before final XOR (check).
+ *
+ * you can get the packet dump from the "write_packets" command. here's the detailed steps.
+ * The -c size of 4 in steps 4 and 7 are chosen to make it easy to delete the right number of lines.
+ * there's nothing magic about the "4".
+ *
+ * 1) execute ./write_packets
+ * 2) xxd -r -c 8 v1_content_nameA_crc32c.txt > y
+ * 3) vim -b y
+ * 4) :%!xxd -p -c 4
+ * 5) Delete the frist 44 bytes (11 lines). The first line should now be:
+ * 00020015
+ * 6) Delete the last 8 bytes
+ * The last line two lines should be:
+ * 04000200
+ * 00
+ * What's left is the part to be signed.
+ * 7) :%!xxd -r -p -c 4
+ * 8) :wq
+ * 9) dump the file to one long URL-escaped hex string with
+ * xxd -p -c 256 y | sed 's/[0-9a-f]\{2\}/%&/g'
+ * 10) Copy the hex string to the website and use the settings specified above (don't use 0x in front
+ * of any hex strings). Click "compute!"
+ * 11) The answer should be 2C3CC0Af
+ * 12) Put the byte array from (11) in the Validation Payload.
+ *
+ */
+
+#ifndef v1_content_nameA_crc32c_h
+#define v1_content_nameA_crc32c_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h>
+
+/**
+ * A well formed interest with only a name
+ */
+
+__attribute__((unused))
+static uint8_t v1_content_nameA_crc32c[] = {
+ 0x01, 0x01, 0x00, 85, // ver = 1, type = content object, length = 85
+ 0x00, 0x00, 0x00, 44, // HopLimit = 31, reserved = 0, header length = 44
+ // ------------------------
+ 0x00, 0x04, 0x00, 20, // ContentObject Fragment, length = 20
+ 0x12, 0x23, 0x34, 0x45,
+ 0x56, 0x67, 0x78, 0x89, // fragid 0x1223344556677889
+ 0x05, 0xDC, 0x01, 0x00, // MTU 1500, fragcnt 1, fragnum 0
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, // interest fragment 0x0102030405060708
+ // ------------------------
+ 0x00, 0x02, 0x00, 8, // Recommended Cache Time
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x6D, 0xDD, 0x00, // 2 hours (0x6DDD00 milli seconds)
+ // ------------------------
+ 0x00, 0x02, 0x00, 21, // type = content object, length = 21
+ // ------------------------
+ 0x00, 0x00, 0x00, 0x11, // type = name, length = 17
+ 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+ // ------------------------
+ 0x00, 0x03, 0x00, 4, // validation alg, length = 4
+ 0x00, 0x02, 0x00, 0x00, // CRC32C
+ // ------------------------
+ 0x00, 0x04, 0x00, 4, // validation payload
+ 0x2C, 0x3C, 0xC0, 0xAF // 2C3CC0AF
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_content_nameA_crc32c)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_E2EFRAG, .bodyManifest = false, .extent = { 12, 20 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_RecommendedCacheTime, .bodyManifest = false, .extent = { 36, 8 } },
+
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 48, 21 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_NAME, .bodyManifest = true, .extent = { 52, 17 } },
+
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_ValidationAlg, .bodyManifest = true, .extent = { 73, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_SIGBITS, .bodyManifest = true, .extent = { 81, 4 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_content_nameA_crc32c_truthTable TABLEENTRY(v1_content_nameA_crc32c, TLV_ERR_NO_ERROR)
+
+#define v1_content_nameA_crc32c_URI "lci:/3=hello/0xf000=ouch"
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h
new file mode 100644
index 00000000..ef37fb5e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file interest_nameA_crc32c.h
+ * @brief Interest with CRC validation
+ *
+ * Signature generated using "openssl sha -sign test_rsa_key.pem -sha256 -binary y > sig", where "y" is
+ * generated from the "xxd -r" of the message hex dump. You need to manually edit "y" so it only
+ * contains the parts begin signed. Then use "xxd -i sig" to get the byte array.
+ *
+ * you can get the dump from the "write_packets" command. here's the detailed steps:
+ *
+ * 1) execute ./write_packets
+ * 2) xxd -r -c 8 v1_content_nameA_keyid1_rsasha256.txt > y
+ * 3) vim -b y
+ * 4) :%!xxd -p -c 16
+ * 5) Delete the frist 32 bytes (2 lines). The first line should now be:
+ * 0002003a000000110002000568656c6c
+ * 6) Delete the last 132 bytes (9 lines, 8 full lines plus the last 4 byte line)
+ * The last line in the file should now be:
+ * 0f3592ae7027fbd2e41e270203010001
+ * What's left is the part to be signed.
+ * 7) :%!xxd -r -p -c 16
+ * 8) :wq
+ * 9) Copy the PEM blocks below and put them in the file "key.pem". Make sure to remove
+ * any leading whitespace. If you get an error in the next command like
+ * "53999:error:0906D06C:PEM routines:PEM_read_bio:no start ... 648:Expecting: ANY PRIVATE KEY" then
+ * you most likely have leading whitespace. Make sure all lines are flush left.
+ * 10) openssl sha -sign key.pem -sha256 -binary y > sig
+ * 11) xxd -i sig
+ * 12) Put the byte array from (11) in the Validation Payload. Verify the length, it should be
+ * 128 bytes. If not, fixup the length of the ValidatonPayload and the PacketLength.
+ *
+ */
+
+/*
+ * -----BEGIN RSA PRIVATE KEY-----
+ * MIICXAIBAAKBgQCn1pPF8XPGErX6ecXvGIvvqs0EAY+Ddz+xZqFauTkqsj4w+xH8
+ * V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEOJEKN5nWgTgRDDD5MBnRnrYTD
+ * 6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8qPD0PNZKucCf70uQeJwIDAQAB
+ * AoGAVOYPA/7aIGSQlu4IOKTDDG3qnM8pSEgG+PbAQgMVrspQ+TfXZj0ftLj++P3N
+ * zpDw8P6BVUfBQs2FNG/ZwEhaiZVgJAl7cIAxJ9Ac+1oZYSgGyJfb3u9iWvkbMOoj
+ * 83Inx5yyN+Qmk5zceH4pOC5D5cDAuGGZ740Euv4o2/2O3qECQQDTmWZw021PvEbA
+ * r18O1YfZGxO3zFCwFXCpnHvtSMbP+MXAG5Gt47wZt4Vx1rX9k78beeCUitwqp3d3
+ * ZI+YlUu3AkEAyw5wssQsJty/n2FL8DbJN3UzUhkcaCFYrKz3RtFye9wu+Bw0TxPC
+ * 3jhFVcynm3nH3ZJN0JsnsPnHXuoQToShEQJATXC51hb6zZC5UDGel348fo9zUvP6
+ * n8bo+ZoknL3izSBdtyYf1cUgBUVuGDCdYFWfPn4HXDXJx+6MQWzTRON21wJBAMZL
+ * U8M/z94jtP3wBjiPR/Dggz2pSBRofDAkuVZvM13BqByjbnHK2oIocY1YTlWGl6fJ
+ * ODR/UEODqS8HZOVIoAECQANcuvVnqDixSIl2ySZvydQytv4DKTbvE0nYSRroYIlJ
+ * PTOBPy8ynIUkJwc2E1BsLl7V8gO62a5O0ntTwBMnPSQ=
+ * -----END RSA PRIVATE KEY-----
+ *
+ * -----BEGIN PUBLIC KEY-----
+ * MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn1pPF8XPGErX6ecXvGIvvqs0E
+ * AY+Ddz+xZqFauTkqsj4w+xH8V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEO
+ * JEKN5nWgTgRDDD5MBnRnrYTD6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8q
+ * PD0PNZKucCf70uQeJwIDAQAB
+ * -----END PUBLIC KEY-----
+ */
+
+#ifndef v1_content_nameA_keyid1_rsasha256_h
+#define v1_content_nameA_keyid1_rsasha256_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h>
+
+/**
+ * A well formed interest with only a name
+ */
+
+
+__attribute__((unused))
+static uint8_t v1_content_nameA_keyid1_rsasha256[] = {
+ 0x01, 0x01, 0x01, 0xB4,// ver = 1, type = content object, length = 436
+ 0x00, 0x00, 0x00, 32, // HopLimit = 0, reserved = 0, header length = 32
+ // ------------------------
+ 0x00, 0x04, 0x00, 20, // ContentObject Fragment, length = 20
+ 0x12, 0x23, 0x34, 0x45,
+ 0x56, 0x67, 0x78, 0x89,// fragid 0x1223344556677889
+ 0x05, 0xDC, 0x01, 0x00,// MTU 1500, fragcnt 1, fragnum 0
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,// interest fragment 0x0102030405060708
+ // ------------------------
+ 0x00, 0x02, 0x00, 58, // type = content object, length = 58
+ // ------------------------
+ 0x00, 0x00, 0x00, 17, // type = name, length = 17
+ 0x00, 0x03, 0x00, 0x05,// type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ 0xF0, 0x00, 0x00, 0x04,// type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+ // ------------------------
+ 0x00, 0x05, 0x00, 1, // PayloadType
+ 1, // type 1 = key
+ 0x00, 0x06, 0x00, 0x08,// expiry time in msec
+ 0x00, 0x00, 0x01, 0x43,// 1,388,534,400,000 msec
+ 0x4B, 0x19, 0x84, 0x00,
+ 0x00, 0x19, 0x00, 4, // end chunk number
+ 0x06, 0x05, 0x04, 0x03,
+ // ------------------------
+ 0x00, 0x01, 0x00, 8, // payload, length = 8
+ 0x73, 0x75, 0x72, 0x70,
+ 0x72, 0x69, 0x73, 0x65,
+ // ------------------------
+ 0x00, 0x03, 0x00, 206, // validation alg, length = 206
+ 0x00, 0x06, 0x00, 202, // RSA-SHA256, length = 162 + 4 + 32 + 4 = 202
+ 0x00, 0x09, 0x00, 32, // type = keyid, length = 32
+ 0x5c, 0x23, 0x4c, 0x28,
+ 0x50, 0xda, 0x20, 0x7b,
+ 0x88, 0x25, 0x8b, 0xf3,
+ 0x62, 0x61, 0x96, 0xd8,
+ 0xf0, 0x60, 0x76, 0x38,
+ 0xa2, 0xd4, 0xe0, 0xe2,
+ 0x49, 0xb2, 0xa9, 0xaf,
+ 0xce, 0xb8, 0x85, 0x59,
+ 0x00, 0x0B, 0x00, 162, // public key, length = 162
+ 0x30, 0x81, 0x9f, 0x30,0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x01,0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81,
+ 0x89, 0x02, 0x81, 0x81,0x00, 0xa7, 0xd6, 0x93, 0xc5, 0xf1, 0x73, 0xc6,
+ 0x12, 0xb5, 0xfa, 0x79,0xc5, 0xef, 0x18, 0x8b, 0xef, 0xaa, 0xcd, 0x04,
+ 0x01, 0x8f, 0x83, 0x77,0x3f, 0xb1, 0x66, 0xa1, 0x5a, 0xb9, 0x39, 0x2a,
+ 0xb2, 0x3e, 0x30, 0xfb,0x11, 0xfc, 0x57, 0xfc, 0x9d, 0xd1, 0x2f, 0x77,
+ 0xf0, 0xab, 0x77, 0xad,0x66, 0x2c, 0x26, 0xc8, 0x9b, 0x51, 0x6f, 0x69,
+ 0xbf, 0x26, 0x10, 0x06,0x29, 0xee, 0xcb, 0xb0, 0x2c, 0x5e, 0x91, 0x0e,
+ 0x24, 0x42, 0x8d, 0xe6,0x75, 0xa0, 0x4e, 0x04, 0x43, 0x0c, 0x3e, 0x4c,
+ 0x06, 0x74, 0x67, 0xad,0x84, 0xc3, 0xe8, 0xf4, 0xc5, 0x94, 0x73, 0xc4,
+ 0x9f, 0x25, 0xa8, 0x42,0x06, 0xbf, 0x45, 0x19, 0xe2, 0x98, 0x1c, 0x36,
+ 0xa1, 0x43, 0x4d, 0x9b,0x71, 0x08, 0xe1, 0x82, 0xdf, 0xe2, 0x4f, 0x2a,
+ 0x3c, 0x3d, 0x0f, 0x35,0x92, 0xae, 0x70, 0x27, 0xfb, 0xd2, 0xe4, 0x1e,
+ 0x27, 0x02, 0x03, 0x01,0x00, 0x01,
+ // ------------------------
+ 0x00, 0x04, 0x00, 128, // validation payload, length = 128
+ 0x03, 0x46, 0xee, 0xb7,0x30, 0x1c, 0xea, 0x13, 0x0c, 0xce, 0x83, 0x5b,
+ 0x7b, 0x4f, 0xf5, 0x83,0x37, 0x08, 0x7f, 0xe0, 0xe1, 0xc9, 0x70, 0x09,
+ 0x5e, 0xc2, 0x1c, 0xd3,0x74, 0xbb, 0xbd, 0x72, 0x35, 0xa4, 0x1b, 0x0f,
+ 0x3d, 0x04, 0x5e, 0xf7,0xc1, 0xdf, 0xea, 0xc3, 0x50, 0x47, 0x14, 0xf9,
+ 0xb7, 0xbb, 0x42, 0xf9,0x3e, 0xaa, 0x49, 0xd2, 0x9f, 0xd1, 0xab, 0xf6,
+ 0xda, 0x32, 0x4a, 0xb1,0xb9, 0x69, 0x91, 0x57, 0x43, 0x5d, 0x06, 0xcf,
+ 0x1d, 0x9f, 0x7c, 0x28,0xee, 0x35, 0xaa, 0xd0, 0xb2, 0x8d, 0x34, 0x09,
+ 0xcd, 0xdb, 0x01, 0xf7,0xda, 0xe8, 0x59, 0x98, 0x4e, 0x59, 0xfa, 0x13,
+ 0xd0, 0xd1, 0x54, 0x8e,0x64, 0x8c, 0xc6, 0xd7, 0x6b, 0xc5, 0x89, 0xeb,
+ 0x37, 0x8f, 0x53, 0x04,0xba, 0x03, 0x05, 0xb4, 0x67, 0x73, 0xe1, 0x51,
+ 0x59, 0x12, 0xbc, 0x25,0xaa, 0xa2, 0xc1, 0x18
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_E2EFRAG, .bodyManifest = false, .extent = { 12, 20 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 36, 58 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_NAME, .bodyManifest = true, .extent = { 40, 17 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PAYLOADTYPE, .bodyManifest = true, .extent = { 61, 1 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_EXPIRY_TIME, .bodyManifest = true, .extent = { 66, 8 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_ENDSEGMENT, .bodyManifest = true, .extent = { 78, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PAYLOAD, .bodyManifest = true, .extent = { 86, 8 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_ValidationAlg, .bodyManifest = true, .extent = { 94, 206 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_KEYID, .bodyManifest = true, .extent = { 106, 32 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PUBKEY, .bodyManifest = true, .extent = { 142, 162 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_SIGBITS, .bodyManifest = true, .extent = { 308, 128 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_content_nameA_keyid1_rsasha256_truthTable TABLEENTRY(v1_content_nameA_keyid1_rsasha256, TLV_ERR_NO_ERROR)
+
+#define v1_content_nameA_keyid1_rsasha256_URI "lci:/3=hello/0xf000=ouch"
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h
new file mode 100644
index 00000000..f1fc59cb
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file v1_content_nameless_nosig.h
+ * @brief A v1 content object without a name
+ *
+ */
+
+#ifndef v1_content_nameless_nosig_h
+#define v1_content_nameless_nosig_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h>
+
+/**
+ * A well formed nameless V1 Content Object
+ */
+__attribute__((unused))
+static uint8_t v1_content_nameless_nosig[] = {
+ 0x01, 0x01, 0x00, 0x31, // ver = 1, type = content object, length = 0x31
+ 0x00, 0x00, 0x00, 0x08, // HopLimit = 0, reserved = 0, header length = 8
+ // ------------------------
+ 0x00, 0x02, 0x00, 37, // type = content object, length = 37
+ // ------------------------
+ 0x00, 0x05, 0x00, 1, // PayloadType
+ 1, // type 1 = key
+ 0x00, 0x06, 0x00, 0x08, // expiry time in msec
+ 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec
+ 0x4B, 0x19, 0x84, 0x00,
+ 0x00, 0x19, 0x00, 4, // end chunk number
+ 0x06, 0x05, 0x04, 0x03,
+ // ------------------------
+ 0x00, 0x01, 0x00, 8, // payload, length = 8
+ 0x73, 0x75, 0x72, 0x70,
+ 0x72, 0x69, 0x73, 0x65,
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_content_nameless_nosig)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 12, 37 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PAYLOADTYPE, .bodyManifest = true, .extent = { 17, 1 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_EXPIRY_TIME, .bodyManifest = true, .extent = { 22, 8 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_ENDSEGMENT, .bodyManifest = true, .extent = { 30, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PAYLOAD, .bodyManifest = true, .extent = { 41, 8 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_content_nameless_nosig_truthTable TABLEENTRY(v1_content_nameless_nosig, TLV_ERR_NO_ERROR)
+
+#endif // v1_content_nameless_nosig_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h
new file mode 100644
index 00000000..ae439bf5
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file v1_content_no_payload.h
+ * @brief Content Object without a payload TLV
+ *
+ *
+ */
+
+
+#ifndef CCNx_Common_v1_content_no_payload_h
+#define CCNx_Common_v1_content_no_payload_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h>
+
+__attribute__((unused))
+static uint8_t v1_content_no_payload[] = {
+ 0x01, 0x01, 0x00, 0x21,
+ 0x00, 0x00, 0x00, 0x08,
+ // -- content object
+ 0x00, 0x02, 0x00, 0x15,
+ // -- name
+ 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x03, 0x00, 0x02,
+ 0x6e, 0x6f,
+ 0x00, 0x03, 0x00, 0x07,
+ 0x70, 0x61, 0x79, 0x6c,
+ 0x6f, 0x61, 0x64
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_content_no_payload)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 12, 21 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_content_no_payload_truthTable TABLEENTRY(v1_content_no_payload, TLV_ERR_NO_ERROR)
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h
new file mode 100644
index 00000000..01f7a8b4
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file v1_content_zero_payload.h
+ * @brief Content Object with zero length payload
+ *
+ *
+ */
+
+
+#ifndef CCNx_Common_v1_content_zero_payload_h
+#define CCNx_Common_v1_content_zero_payload_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h>
+
+__attribute__((unused))
+static uint8_t v1_content_zero_payload[] = {
+ 0x01, 0x01, 0x00, 0x25,
+ 0x00, 0x00, 0x00, 0x08,
+ // -- content object
+ 0x00, 0x02, 0x00, 0x19,
+ // -- name
+ 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x03, 0x00, 0x02,
+ 0x6e, 0x6f,
+ 0x00, 0x03, 0x00, 0x07,
+ 0x70, 0x61, 0x79, 0x6c,
+ 0x6f, 0x61, 0x64,
+ // -- payload
+ 0x00, 0x01, 0x00, 0x00,
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_content_zero_payload)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 12, 25 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_content_zero_payload_truthTable TABLEENTRY(v1_content_zero_payload, TLV_ERR_NO_ERROR)
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h
new file mode 100644
index 00000000..9bcf7dfc
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file v1_cpi_add_route.h
+ * @brief A hand-encoded CPI packet to add a route
+ *
+ * The v1 old-style control packet is a fixed header plus a tlv container 0xBEEF with a "value" of the CPI JSON string.
+ * The packet type is 0xA4.
+ *
+ */
+
+#ifndef TransportRTA_v1_cpi_AddRoute_h
+#define TransportRTA_v1_cpi_AddRoute_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h>
+
+__attribute__((unused))
+static uint8_t v1_cpi_add_route[] = "\x01\xA4\x00\xA7"
+ "\x00\x00\x00\x08"
+ "\xBE\xEF\x00\x9A"
+ "{\"CPI_REQUEST\":{\"SEQUENCE\":22,\"REGISTER\":{\"PREFIX\":\"lci:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}";
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_cpi_add_route)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_CPI_PAYLOAD, .bodyManifest = true, .extent = { 12, 155 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_cpi_add_route_truthTable TABLEENTRY(v1_cpi_add_route, TLV_ERR_NO_ERROR)
+
+#define v1_cpi_add_route_PrefixUri "lci:/howdie/stranger"
+#define v1_cpi_add_route_Sequence 22
+#define v1_cpi_add_route_Interface 55
+#endif // TransportRTA_cpi_AddRoute_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h
new file mode 100644
index 00000000..e31cfc85
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file v1_cpi_add_route.h
+ * @brief A hand-encoded CPI packet to add a route
+ *
+ * The v1 old-style control packet is a fixed header plus a tlv container 0xBEEF with a "value" of the CPI JSON string.
+ * The packet type is 0xA4.
+ *
+ * This control packet has a CRC32C MIC on it. Otherwise, same as v1_cpi_add_route.h
+ *
+ * Ground truth set derived from CRC RevEng http://reveng.sourceforge.net
+ * e.g. reveng -c -m CRC-32C 313233343536373839 gives the canonical check value 0xe306928e
+ *
+ * You can also calcaulate CRC32C online at http://www.zorc.breitbandkatze.de/crc.html using
+ * CRC polynomial 0x1EDC6F41, init 0xFFFFFFFF, final 0xFFFFFFFF, reverse data bytes (check),
+ * and reverse CRC result before final XOR (check).
+ *
+ * you can get the packet dump from the "write_packets" command. here's the detailed steps.
+ * The -c size of 4 in steps 4 and 7 are chosen to make it easy to delete the right number of lines.
+ * there's nothing magic about the "4".
+ *
+ * 1) execute ./write_packets
+ * 2) xxd -r -c 8 v1_cpi_add_route_crc32c.txt > y
+ * 3) Delete the first 8 bytes and last 16 bytes and display has a hex string
+ * tail -c +9 y | head -c 158 | xxd -p -c 256
+ * The string should be "beef...077d7d7d"
+ * 4) The string for this packet is too long for the website. Use another tool such as reveng.
+ * 5) The answer should be 78fd926a (the reveng answer will be byte reversed)
+ * 6) Put the byte array from (5) in the Validation Payload.
+ *
+ */
+
+#ifndef TransportRTA_v1_v1_cpi_AddRoute_crc32c_h
+#define TransportRTA_v1_v1_cpi_AddRoute_crc32c_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h>
+
+__attribute__((unused))
+static uint8_t v1_cpi_add_route_crc32c[] = "\x01\xA4\x00\xB7"
+ "\x00\x00\x00\x08"
+ "\xBE\xEF\x00\x9A"
+ "{\"CPI_REQUEST\":{\"SEQUENCE\":22,\"REGISTER\":{\"PREFIX\":\"lci:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}"
+ "\x00\x03\x00\x04"
+ "\x00\x02\x00\x00"
+ "\x00\x04\x00\x04"
+ "\x78\xfd\x92\x6a";
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_cpi_add_route_crc32c)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_CPI_PAYLOAD, .bodyManifest = true, .extent = { 12, 155 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_CPI_ValidationAlg, .bodyManifest = true, .extent = { 171, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_CPI_SIGBITS, .bodyManifest = true, .extent = { 178, 4 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_cpi_add_route_crc32c_truthTable TABLEENTRY(v1_cpi_add_route_crc32c, TLV_ERR_NO_ERROR)
+
+#define v1_cpi_add_route_crc32c_PrefixUri "lci:/howdie/stranger"
+#define v1_cpi_add_route_crc32c_Sequence 22
+#define v1_cpi_add_route_crc32c_Interface 55
+#endif // TransportRTA_cpi_AddRoute_h
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h
new file mode 100755
index 00000000..f6524ad1
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file v1_interest_all_fields.h
+ * @brief A hand-encoded v1 interest in wireformat with all Interest fields.
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef CCNx_Common_v1_interest_all_fields_h
+#define CCNx_Common_v1_interest_all_fields_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+/**
+ * A well formed interest with all allowed Interest fields
+ */
+__attribute__((unused))
+static uint8_t v1_interest_all_fields[] = {
+ 0x01, 0x00, 0x00, 156, // ver = 1, type = interest, length = 156
+ 0x20, 0x00, 0x11, 14, // HopLimit = 32, reserved = 0, flags = 0x11, header length = 14
+ // ------------------------
+ 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes)
+ 0xEA, 0xEB,
+ // ------------------------
+ 0x00, 0x01, 0x00, 138, // type = interest, length = 138
+ // ------------------------
+ 0x00, 0x00, 0x00, 45, // type = name, length = 45
+ 0x00, 0x03, 0x00, 4, // type = binary, length = 4
+ 'c', 'o', 'o', 'l', // "cool"
+ // ----- segment 2 --------
+ 0x00, 0x02, 0x00, 33, // type = payload id, length = 33
+ 0x01, // payloadID type = sha256
+ 0x89, 0x87, 0x69, 0xfc, // hash bytes based on payload
+ 0x8c, 0xff, 0x16, 0xff,
+ 0x3d, 0xfc, 0xe7, 0xfa,
+ 0x02, 0xd2, 0x6d, 0x26,
+ 0xf0, 0x91, 0x86, 0x27,
+ 0xcf, 0x18, 0xc1, 0x9b,
+ 0x0b, 0x5f, 0xe3, 0x93,
+ 0xce, 0x1a, 0xa3, 0x56,
+ // ------------------------
+ 0x00, 0x02, 0x00, 36, // type = keyid restriction, length = 36
+ 0x00, 0x01, 0x00, 0x20, // SHA256 hash, length 32
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab,
+ 0xac, 0xad, 0xae, 0xaf,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab,
+ 0xac, 0xad, 0xae, 0xaf,
+ // ------------------------
+ 0x00, 0x03, 0x00, 36, // type = hash restriction, length = 36
+ 0x00, 0x01, 0x00, 0x20, // SHA256 hash, length 32
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb,
+ 0xcc, 0xcd, 0xce, 0xcf,
+ // ------------------------
+ 0x00, 0x01, 0x00, 5, // type = payload, length = 5
+ 0xD0, 0xD1, 0xD2, 0xD3,
+ 0xD4,
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_all_fields)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_LIFETIME, .bodyManifest = false, .extent = { 12, 2 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 18, 138 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 22, 45 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_KEYID, .bodyManifest = true, .extent = { 71, 36 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_OBJHASH, .bodyManifest = true, .extent = { 111, 36 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_PAYLOAD, .bodyManifest = true, .extent = { 151, 5 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_interest_all_fields_truthTable TABLEENTRY(v1_interest_all_fields, TLV_ERR_NO_ERROR)
+
+#define v1_interest_all_fields_URI "lci:/3=cool/2=\x01\x89\x87\x69\xfc\x8c\xff\x16\xff\x3d\xfc\xe7\xfa\x02\xd2\x6d\x26\xf0\x91\x86\x27\xcf\x18\xc1\x9b\x0b\x5f\xe3\x93\xce\x1a\xa3\x56"
+#define v1_interest_all_fields_Lifetime 0xEAEB
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h
new file mode 100644
index 00000000..650c770e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file v1_interest_all_fields.h
+ * @brief A hand-encoded v1 interest in wireformat with all Interest fields.
+ *
+ * The Interest TLV length goes beyond the end of the packet
+ *
+ */
+
+#ifndef CCNx_Common_v1_interest_bad_message_length_h
+#define CCNx_Common_v1_interest_bad_message_length_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+/**
+ * A well formed interest with all allowed Interest fields
+ */
+__attribute__((unused))
+static uint8_t v1_interest_bad_message_length[] = {
+ 0x01, 0x00, 0x00, 30, // ver = 1, type = interest, length = 30
+ 0x20, 0x00, 0x11, 14, // HopLimit = 31, reserved = 0, flags = 0x11, header length = 14
+ // ------------------------
+ 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes)
+ 0xEA, 0xEB,
+ // ------------------------
+ 0x00, 0x01, 0x00, 13, // type = interest, length = 13 (1 byte too far)
+ // ------------------------
+ 0x00, 0x00, 0x00, 8, // type = name, length = 8
+ 0x00, 0x03, 0x00, 4, // type = binary, length = 4
+ 'c', 'o', 'o', 'l', // "cool"
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_bad_message_length)[] =
+{
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_interest_bad_message_length_truthTable TABLEENTRY(v1_interest_bad_message_length, TLV_ERR_TOO_LONG)
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h
new file mode 100644
index 00000000..9c4c3117
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file v1_interest_bad_validation_alg.h
+ * @brief Interest with CRC validation
+ *
+ * This is an error packet, the ValidationAlg TLV does not have the correct type
+ *
+ */
+
+#ifndef testdata_v1_interest_bad_validation_alg
+#define testdata_v1_interest_bad_validation_alg
+
+/**
+ * A well formed interest with only a name
+ */
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+__attribute__((unused))
+static uint8_t v1_interest_bad_validation_alg[] = {
+ 0x01, 0x00, 0x00, 65, // ver = 1, type = interest, length = 65
+ 0x20, 0x00, 0x00, 24, // HopLimit = 32, reserved = 0, header length = 24
+ // ------------------------
+ 0x00, 0x03, 0x00, 12, // Interest Fragment
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708
+ 0x05, 0xDC, 0x00, 0x00, // MTU 1500, fragcnt 0, fragnum 0
+ // ------------------------
+ 0x00, 0x01, 0x00, 0x15, // type = interest, length = 21
+ // ------------------------
+ 0x00, 0x00, 0x00, 0x11, // type = name, length = 17
+ 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+ // ------------------------
+ 0x00, 0xFF, 0x00, 4, // Not "0x03" validation alg length = 4
+ 0x00, 0xFF, 0x00, 0x00, // unknown validation alg
+ // ------------------------
+ 0x00, 0x04, 0x00, 4, // validation payload
+ 0x6A, 0xD7, 0xB1, 0xF2 // 6AD7B1F2
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_bad_validation_alg)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 24, 25 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 32, 17 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationAlg, .bodyManifest = true, .extent = { 53, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationPayload, .bodyManifest = true, .extent = { 61, 4 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_interest_bad_validation_alg_truthTable TABLEENTRY(v1_interest_bad_validation_alg, TLV_ERR_NO_ERROR)
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h
new file mode 100644
index 00000000..4bee1e40
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file v1_interest_nameA.h
+ * @brief A basic interest
+ *
+ * A basic Interest with a fragmentation header and Name.
+ *
+ */
+
+#ifndef testdata_interest_nameA_h
+#define testdata_interest_nameA_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+/**
+ * A well formed interest with only a name
+ */
+
+
+__attribute__((unused))
+static uint8_t v1_interest_nameA[] = {
+ 0x01, 0x00, 0x00, 61, // ver = 1, type = interest, length = 61
+ 0x20, 0x00, 0x00, 36, // HopLimit = 31, reserved = 0, header length = 36
+ // ------------------------
+ // ------------------------
+ 0x00, 0x03, 0x00, 12, // Interest Fragment
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708
+ 0x05, 0xDC, 0x00, 0x00, // MTU 1500, fragcnt 0, fragnum 0
+ // ------------------------
+ 0x00, 0x01, 0x00, 8, // Interest Lifetime
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0F, 0xA0, // 4000 milli-seconds
+ // ------------------------
+ 0x00, 0x01, 0x00, 0x15, // type = interest, length = 21
+ // ------------------------
+ 0x00, 0x00, 0x00, 0x11, // type = name, length = 17
+ 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_nameA)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_LIFETIME, .bodyManifest = false, .extent = { 28, 8 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = false, .extent = { 40, 21 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 44, 17 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_interest_nameA_truthTable TABLEENTRY(v1_interest_nameA, TLV_ERR_NO_ERROR)
+
+#define v1_interest_nameA_URI "lci:/3=hello/0xf000=ouch"
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_badcrc32c.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_badcrc32c.h
new file mode 100644
index 00000000..6af04f42
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_badcrc32c.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file interest_nameA_badcrc32c.h
+ * @brief Interest with CRC validation
+ *
+ * Has incorrect CRC32C payload
+ *
+ */
+
+#ifndef testdata_interest_nameA_badcrc32c_h
+#define testdata_interest_nameA_badcrc32c_h
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+/**
+ * A well formed interest with only a name
+ */
+
+__attribute__((unused))
+static uint8_t v1_interest_nameA_badcrc32c[] = {
+ 0x01, 0x00, 0x00, 41, // ver = 1, type = interest, length = 65
+ 0x20, 0x00, 0x00, 24, // HopLimit = 31, reserved = 0, header length = 24
+ // ------------------------
+ 0x00, 0x03, 0x00, 0x0C, // Interest Fragment
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708
+ 0x05, 0xDC, 0x00, 0x00, // MTU 1500, fragcnt 0, fragnum 0
+ // ------------------------
+ 0x00, 0x01, 0x00, 0x15, // type = interest, length = 21
+ // ------------------------
+ 0x00, 0x00, 0x00, 0x11, // type = name, length = 17
+ 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+ // ------------------------
+ 0x00, 0x03, 0x00, 4, // validation alg, length = 4
+ 0x00, 0x02, 0x00, 0x00, // CRC32C
+ // ------------------------
+ 0x00, 0x04, 0x00, 4, // validation payload
+ 0x00, 0x00, 0x00, 0x00 // invalid CRC32C
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_nameA_badcrc32c)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 20, 21 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 24, 17 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationAlg, .bodyManifest = true, .extent = { 45, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationPayload, .bodyManifest = true, .extent = { 53, 4 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_interest_nameA_badcrc32c_truthTable TABLEENTRY(v1_interest_nameA_badcrc32c, TLV_ERR_NO_ERROR)
+
+#define v1_interest_nameA_badcrc32c_URI "lci:/3=hello/0xf000=ouch"
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h
new file mode 100644
index 00000000..64edf560
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file interest_nameA_crc32c.h
+ * @brief Interest with CRC validation
+ *
+ *
+ * Ground truth set derived from CRC RevEng http://reveng.sourceforge.net
+ * e.g. reveng -c -m CRC-32C 313233343536373839 gives the canonical check value 0xe306928e (the output will be backwards)
+ *
+ * You can also calcaulate CRC32C online at http://www.zorc.breitbandkatze.de/crc.html using
+ * CRC polynomial 0x1EDC6F41, init 0xFFFFFFFF, final 0xFFFFFFFF, reverse data bytes (check),
+ * and reverse CRC result before final XOR (check).
+ *
+ * you can get the packet dump from the "write_packets" command. here's the detailed steps.
+ * The -c size of 8 in steps 4 and 7 are chosen to make it easy to delete the right number of lines.
+ * there's nothing magic about the "8".
+ *
+ * 1) execute ./write_packets
+ * 2) xxd -r -c 8 v1_interest_nameA_crc32c.txt > y
+ * 3) Delete the first 24 bytes and last 8 bytes and display as a URI-escaped hex string
+ * head -c 57 y | tail -c +25 | xxd -p -c 256 | sed 's/[0-9a-f]\{2\}/%&/g'
+ * The string should be "00010015...00020000"
+ * 4) Copy the hex string to the website and use the settings specified above (don't use 0x in front
+ * of any hex strings). IMPORTANT: you need to %-escape each hex byte!! Click "compute!"
+ * 5) The answer should be 6AD7B1F2
+ * 6) Put the byte array from (5) in the Validation Payload.
+ *
+ */
+
+#ifndef testdata_interest_nameA_crc32c_h
+#define testdata_interest_nameA_crc32c_h
+
+/**
+ * A well formed interest with only a name
+ */
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+#define NAME_A_CRC32_PACKET(_type, _code) \
+ { \
+ 0x01, _type, 0x00, 65, /* ver = 1, type = interest, length = 65 */ \
+ 0x20, _code, 0x00, 24, /* HopLimit = 32, reserved = 0, header length = 24*/ \
+ /* ------------------------ */ \
+ 0x00, 0x03, 0x00, 12, /* Interest Fragment */ \
+ 0x01, 0x02, 0x03, 0x04, \
+ 0x05, 0x06, 0x07, 0x08, /* fragment 0x0102030405060708 */ \
+ 0x05, 0xDC, 0x00, 0x00, /* MTU 1500, fragcnt 0, fragnum 0 */ \
+ /* ------------------------ */ \
+ 0x00, 0x01, 0x00, 0x15, /* type = interest, length = 21 */ \
+ /* ------------------------ */ \
+ 0x00, 0x00, 0x00, 0x11, /* type = name, length = 17 */ \
+ 0x00, 0x03, 0x00, 0x05, /* type = binary, length = 5 */ \
+ 'h', 'e', 'l', 'l', /* "hello" */ \
+ 'o', \
+ 0xF0, 0x00, 0x00, 0x04, /* type = app, length = 4 */ \
+ 'o', 'u', 'c', 'h', /* "ouch" */ \
+ /* ------------------------ */ \
+ 0x00, 0x03, 0x00, 4, /* validation alg, length = 4 */ \
+ 0x00, 0x02, 0x00, 0x00, /* CRC32C */ \
+ /* ------------------------ */ \
+ 0x00, 0x04, 0x00, 4, /* validation payload */ \
+ 0xD0, 0x98, 0x73, 0x7C, /* D098737C */ \
+ }
+
+__attribute__((unused))
+static uint8_t v1_interest_nameA_crc32c[] = NAME_A_CRC32_PACKET(0x00, 0x00);
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_nameA_crc32c)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 24, 25 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 32, 17 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationAlg, .bodyManifest = true, .extent = { 53, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationPayload, .bodyManifest = true, .extent = { 61, 4 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+__attribute__((unused))
+static uint8_t v1_interest_nameA_crc32c_returned[] = NAME_A_CRC32_PACKET(0x02, 0x03); //InterestReturn & NoResource
+
+#define v1_interest_nameA_crc32c_truthTable TABLEENTRY(v1_interest_nameA_crc32c, TLV_ERR_NO_ERROR)
+
+#define v1_interest_nameA_crc32c_URI "lci:/3=hello/0xf000=ouch"
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h
new file mode 100644
index 00000000..8f3b55a5
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file v1_interest_validation_alg_overrun.h
+ * @brief Interest with CRC validation
+ *
+ * This is an error packet. The length of the Validation TLV runs past the end of the packet.
+ *
+ */
+
+#ifndef testdata_v1_interest_validation_alg_overrun
+#define testdata_v1_interest_validation_alg_overrun
+
+/**
+ * A well formed interest with only a name
+ */
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+
+__attribute__((unused))
+static uint8_t v1_interest_validation_alg_overrun[] = {
+ 0x01, 0x00, 0x00, 65, // ver = 1, type = interest, length = 65
+ 0x20, 0x00, 0x00, 24, // HopLimit = 32, reserved = 0, header length = 24
+ // ------------------------
+ 0x00, 0x03, 0x00, 12, // Interest Fragment
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708
+ 0x05, 0xDC, 0x00, 0x00, // MTU 1500, fragcnt 0, fragnum 0
+ // ------------------------
+ 0x00, 0x01, 0x00, 0x15, // type = interest, length = 21
+ // ------------------------
+ 0x00, 0x00, 0x00, 0x11, // type = name, length = 17
+ 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4
+ 'o', 'u', 'c', 'h', // "ouch"
+ // ------------------------
+ 0x00, 0x03, 0x00, 255, // Validation Alg, length = 255
+ 0x00, 0xFF, 0x00, 0x00, // unknown validation alg
+ // ------------------------
+ 0x00, 0x04, 0x00, 4, // validation payload
+ 0x6A, 0xD7, 0xB1, 0xF2 // 6AD7B1F2
+};
+
+__attribute__((unused))
+static TruthTableEntry
+TRUTHTABLENAME(v1_interest_validation_alg_overrun)[] =
+{
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 24, 25 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 32, 17 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationAlg, .bodyManifest = true, .extent = { 53, 4 } },
+ { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationPayload, .bodyManifest = true, .extent = { 61, 4 } },
+ { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } },
+};
+
+#define v1_interest_validation_alg_overrun_truthTable TABLEENTRY(v1_interest_validation_alg_overrun, TLV_ERR_TOO_LONG)
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthSet.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthSet.h
new file mode 100644
index 00000000..f98de878
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthSet.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Contains tables of all the packets. May be used for automated testing. Also used by write_packets utility.
+ *
+ */
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+
+#include "v1_interest_nameA.h"
+#include "v1_interest_nameA_badcrc32c.h"
+#include "v1_interest_nameA_crc32c.h"
+#include "v1_interest_bad_validation_alg.h"
+#include "v1_interest_validation_alg_overrun.h"
+
+#include "v1_content_nameA_crc32c.h"
+#include "v1_content_nameA_keyid1_rsasha256.h"
+#include "v1_content_zero_payload.h"
+#include "v1_content_no_payload.h"
+
+#include "v1_cpi_add_route.h"
+#include "v1_cpi_add_route_crc32c.h"
+
+// terminated with NULL packet entry
+__attribute__((unused))
+static TruthTable v1_interests_truthSet [] = {
+ // tests in alphabetical order
+ v1_interest_nameA_truthTable,
+ v1_interest_nameA_badcrc32c_truthTable,
+ v1_interest_nameA_crc32c_truthTable,
+ v1_interest_bad_validation_alg_truthTable,
+ v1_interest_validation_alg_overrun_truthTable,
+ // the end of table marker
+ { .packet = NULL, .expectedError= 0, .entry = NULL }
+};
+
+// terminated with NULL packet entry
+__attribute__((unused))
+static TruthTable v1_contentObject_truthSet [] = {
+ v1_content_nameA_crc32c_truthTable,
+ v1_content_nameA_keyid1_rsasha256_truthTable,
+ v1_content_zero_payload_truthTable,
+ v1_content_no_payload_truthTable,
+
+ // the end of table marker
+ { .packet = NULL, .expectedError= 0, .entry = NULL }
+};
+
+__attribute__((unused))
+static TruthTable v1_cpi_truthSet [] = {
+ v1_cpi_add_route_truthTable,
+ v1_cpi_add_route_crc32c_truthTable,
+ // the end of table marker
+ { .packet = NULL, .expectedError= 0, .entry = NULL }
+};
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h
new file mode 100755
index 00000000..32c954b7
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ * testrig_truthTable.h
+ * TransportRTA
+ */
+
+#ifndef TransportRTA_testrig_truthTable_h
+#define TransportRTA_testrig_truthTable_h
+
+#include <ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h>
+//#include <ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <ccnx/common/codec/testdata/testdata_common.h>
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/test/.gitignore b/libccnx-common/ccnx/common/codec/test/.gitignore
new file mode 100644
index 00000000..f0d97bc9
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/.gitignore
@@ -0,0 +1,7 @@
+test_ccnxCodec_EncodingBuffer
+test_ccnxCodec_Error
+test_ccnxCodec_NetworkBuffer
+test_ccnxCodec_TlvDecoder
+test_ccnxCodec_TlvEncoder
+test_ccnxCodec_TlvPacket
+test_ccnxCodec_TlvUtilities
diff --git a/libccnx-common/ccnx/common/codec/test/CMakeLists.txt b/libccnx-common/ccnx/common/codec/test/CMakeLists.txt
new file mode 100644
index 00000000..73dd544e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+configure_file(test_rsa.p12 test_rsa.p12 COPYONLY)
+configure_file(test_random_bytes test_random_bytes COPYONLY)
+configure_file(test_random_bytes.sig test_random_bytes.sig COPYONLY)
+configure_file(test_rsa_key.pem test_rsa_key.pem COPYONLY)
+
+set(TestsExpectedToPass
+ test_ccnxCodec_EncodingBuffer
+ test_ccnxCodec_Error
+ test_ccnxCodec_NetworkBuffer
+ test_ccnxCodec_TlvDecoder
+ test_ccnxCodec_TlvEncoder
+ test_ccnxCodec_TlvPacket
+ test_ccnxCodec_TlvUtilities
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_EncodingBuffer.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_EncodingBuffer.c
new file mode 100755
index 00000000..33bdbbc7
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_EncodingBuffer.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodec_EncodingBuffer.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+typedef struct test_data {
+ CCNxCodecEncodingBuffer *encodingBuffer;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->encodingBuffer = ccnxCodecEncodingBuffer_Create();
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ ccnxCodecEncodingBuffer_Release(&data->encodingBuffer);
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(ccnxCodec_EncodingBuffer)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxCodec_EncodingBuffer)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodec_EncodingBuffer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_FirstAppend);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_SameArray);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_SecondArray);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_Create);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_CreateIOVec);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_CreateIOVec_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_Display);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecEncodingBuffer_Length);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_FirstAppend)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Wrap("hello", 5, 0, 5);
+ size_t position = ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer);
+ assertTrue(position == 0, "Wrong position, got %zu expected %d", position, 0);
+
+ _ccnxCodecEncodingBuffer_Validate(data->encodingBuffer);
+ assertTrue(data->encodingBuffer->totalCount == 1, "Wrong count, got %u expected %u", data->encodingBuffer->totalCount, 1);
+ assertTrue(data->encodingBuffer->totalBytes == 5, "Wrong bytes, got %zu expected %u", data->encodingBuffer->totalBytes, 5);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_SameArray)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Wrap("hello", 5, 0, 5);
+
+ // do two appends
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer);
+ size_t position = ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer);
+ assertTrue(position == 1, "Wrong position, got %zu expected %d", position, 1);
+
+ _ccnxCodecEncodingBuffer_Validate(data->encodingBuffer);
+ assertTrue(data->encodingBuffer->totalCount == 2, "Wrong count, got %u expected %u", data->encodingBuffer->totalCount, 2);
+ assertTrue(data->encodingBuffer->totalBytes == 10, "Wrong bytes, got %zu expected %u", data->encodingBuffer->totalBytes, 10);
+
+ // should still be in the first listarray
+ assertTrue(data->encodingBuffer->head == data->encodingBuffer->tail, "Head != tail")
+ {
+ ccnxCodecEncodingBuffer_Display(data->encodingBuffer, 0);
+ }
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_AppendBuffer_SecondArray)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Wrap("hello", 5, 0, 5);
+
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer);
+
+ // now fake out the list array so it thinks its full.
+ // Do this by reducing the capacity so there are no undefined buffers on the list
+ data->encodingBuffer->head->capacity = data->encodingBuffer->head->count;
+
+ size_t position = ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer);
+ assertTrue(position == 1, "Wrong position, got %zu expected %u", position, 1);
+
+ _ccnxCodecEncodingBuffer_Validate(data->encodingBuffer);
+ assertTrue(data->encodingBuffer->totalCount == 2, "Wrong count, got %u expected %u", data->encodingBuffer->totalCount, 2);
+ assertTrue(data->encodingBuffer->totalBytes == 10, "Wrong bytes, got %zu expected %u", data->encodingBuffer->totalBytes, 10);
+
+ // should now have different head and tail
+ assertTrue(data->encodingBuffer->head != data->encodingBuffer->tail, "Head == tail")
+ {
+ ccnxCodecEncodingBuffer_Display(data->encodingBuffer, 0);
+ }
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Create)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertNotNull(data->encodingBuffer, "Got null buffer from create");
+ assertNull(data->encodingBuffer->head, "buffer head is not null");
+ assertNull(data->encodingBuffer->tail, "Buffer tail is not null");
+ assertTrue(data->encodingBuffer->totalCount == 0, "Buffer itemCount is not 0");
+ assertTrue(data->encodingBuffer->totalBytes == 0, "Buffer totalBytes is not 0");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_CreateIOVec)
+{
+ char foo[] = "foo";
+ char bar[] = "barbar";
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer_1 = parcBuffer_Wrap(foo, sizeof(foo), 0, sizeof(foo));
+ PARCBuffer *buffer_2 = parcBuffer_Wrap(bar, sizeof(bar), 0, sizeof(bar));
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_2);
+ ccnxCodecEncodingBuffer_PrependBuffer(data->encodingBuffer, buffer_1);
+
+ CCNxCodecEncodingBufferIOVec *iov = ccnxCodecEncodingBuffer_CreateIOVec(data->encodingBuffer);
+ assertNotNull(iov, "Got null iov from CreateIOVec");
+ assertTrue(iov->iovcnt == 2, "Wrong iovec count, got %d expected %d", iov->iovcnt, 2);
+ assertTrue(iov->iov[0].iov_base == foo, "WRong iov[0].iov_base, got %p exected %p", iov->iov[0].iov_base, foo);
+ assertTrue(iov->iov[1].iov_base == bar, "WRong iov[1].iov_base, got %p exected %p", iov->iov[1].iov_base, bar);
+ assertTrue(iov->iov[0].iov_len == sizeof(foo), "WRong iov[1].iov_base, got %zu exected %zu", iov->iov[0].iov_len, sizeof(foo));
+ assertTrue(iov->iov[1].iov_len == sizeof(bar), "WRong iov[1].iov_base, got %zu exected %zu", iov->iov[1].iov_len, sizeof(bar));
+
+ // Slice crossing two iovec arrays
+ CCNxCodecEncodingBuffer *bufferSlice = ccnxCodecEncodingBuffer_Slice(data->encodingBuffer, 1, 6);
+ CCNxCodecEncodingBufferIOVec *iovSlice = ccnxCodecEncodingBuffer_CreateIOVec(bufferSlice);
+ assertTrue(iovSlice->iovcnt == 2, "Wrong iovec count, got %d expected %d", iovSlice->iovcnt, 2);
+ assertTrue(iovSlice->iov[0].iov_base == foo + 1, "WRong iovSlice[0].iov_base, got %p exected %p", iovSlice->iov[0].iov_base, foo + 1);
+ assertTrue(iovSlice->iov[0].iov_len == sizeof(foo) - 1, "WRong iovSlice[1].iov_len, got %zu exected %zu", iovSlice->iov[0].iov_len, sizeof(foo) - 1);
+ assertTrue(iovSlice->iov[1].iov_len == 6 - (sizeof(foo) - 1), "WRong iovSlice[1].iov_base, got %zu exected %lu", iovSlice->iov[1].iov_len, 6 - (sizeof(foo) - 1));
+ ccnxCodecEncodingBufferIOVec_Release(&iovSlice);
+ ccnxCodecEncodingBuffer_Release(&bufferSlice);
+
+ // Slice within one iovec array
+ bufferSlice = ccnxCodecEncodingBuffer_Slice(data->encodingBuffer, 1, 1);
+ iovSlice = ccnxCodecEncodingBuffer_CreateIOVec(bufferSlice);
+ assertTrue(iovSlice->iovcnt == 1, "Wrong iovec count, got %d expected %d", iovSlice->iovcnt, 1);
+ assertTrue(iovSlice->iov[0].iov_base == foo + 1, "WRong iovSlice[0].iov_base, got %p exected %p", iovSlice->iov[0].iov_base, foo + 1);
+ assertTrue(iovSlice->iov[0].iov_len == 1, "WRong iovSlice[1].iov_len, got %zu exected %d", iovSlice->iov[0].iov_len, 1);
+ ccnxCodecEncodingBufferIOVec_Release(&iovSlice);
+ ccnxCodecEncodingBuffer_Release(&bufferSlice);
+
+ // Slice beyond contents
+ bufferSlice = ccnxCodecEncodingBuffer_Slice(data->encodingBuffer, sizeof(foo) + sizeof(bar), 1);
+ assertNull(bufferSlice, "ccnxCodecEncodingBuffer_Slice returned allocation for slice outside of buffer");
+
+ // Slice including all and beyond
+ bufferSlice = ccnxCodecEncodingBuffer_Slice(data->encodingBuffer, 0, sizeof(foo) + sizeof(bar) + 10);
+ iovSlice = ccnxCodecEncodingBuffer_CreateIOVec(bufferSlice);
+ assertTrue(iovSlice->iovcnt == 2, "Wrong iovec count, got %d expected %d", iovSlice->iovcnt, 2);
+ assertTrue(iovSlice->iov[0].iov_base == foo, "WRong iovSlice[0].iov_base, got %p exected %p", iovSlice->iov[0].iov_base, foo);
+ assertTrue(iovSlice->iov[0].iov_len == sizeof(foo), "WRong iovSlice[1].iov_len, got %zu exected %zu", iovSlice->iov[0].iov_len, sizeof(foo));
+ assertTrue(iovSlice->iov[1].iov_len == sizeof(bar), "WRong iovSlice[1].iov_base, got %zu exected %lu", iovSlice->iov[1].iov_len, sizeof(bar));
+ ccnxCodecEncodingBufferIOVec_Release(&iovSlice);
+ ccnxCodecEncodingBuffer_Release(&bufferSlice);
+
+ ccnxCodecEncodingBufferIOVec_Release(&iov);
+
+ parcBuffer_Release(&buffer_1);
+ parcBuffer_Release(&buffer_2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_CreateIOVec_Empty)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxCodecEncodingBufferIOVec *iov = ccnxCodecEncodingBuffer_CreateIOVec(data->encodingBuffer);
+ assertNotNull(iov, "Got null iov from CreateIOVec");
+ assertTrue(iov->iovcnt == 0, "Wrong iovec count, got %d expected %d", iov->iovcnt, 0);
+
+ // single allocation means that the iov will never be null
+ assertNotNull(iov->iov, "iov->iov should not be null");
+
+ ccnxCodecEncodingBufferIOVec_Release(&iov);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Display)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Wrap("hello", 5, 0, 5);
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer);
+ parcBuffer_Release(&buffer);
+
+ ccnxCodecEncodingBuffer_Display(data->encodingBuffer, 0);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Length)
+{
+ char foo[] = "foo";
+ char bar[] = "barbar";
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer_1 = parcBuffer_Wrap(foo, sizeof(foo), 0, sizeof(foo));
+ PARCBuffer *buffer_2 = parcBuffer_Wrap(bar, sizeof(bar), 0, sizeof(bar));
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_1);
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_2);
+
+ size_t length = ccnxCodecEncodingBuffer_Length(data->encodingBuffer);
+ size_t truth = sizeof(foo) + sizeof(bar);
+ assertTrue(length == truth, "Wrong length, got %zu expected %zu", length, truth);
+
+ parcBuffer_Release(&buffer_1);
+ parcBuffer_Release(&buffer_2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Size)
+{
+ char foo[] = "foo";
+ char bar[] = "barbar";
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer_1 = parcBuffer_Wrap(foo, sizeof(foo), 0, sizeof(foo));
+ PARCBuffer *buffer_2 = parcBuffer_Wrap(bar, sizeof(bar), 0, sizeof(bar));
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_1);
+ ccnxCodecEncodingBuffer_AppendBuffer(data->encodingBuffer, buffer_2);
+
+ size_t size = ccnxCodecEncodingBuffer_Size(data->encodingBuffer);
+ assertTrue(size == 2, "Wrong size, got %zu expected %u", size, 2);
+
+ parcBuffer_Release(&buffer_1);
+ parcBuffer_Release(&buffer_2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecEncodingBuffer_Example)
+{
+ PARCBuffer *name = parcBuffer_Wrap("marc", 4, 0, 4);
+ PARCBuffer *space = parcBuffer_Wrap(" ", 1, 0, 1);
+ PARCBuffer *email = parcBuffer_Wrap("<marc@example.com>", 18, 0, 18);
+
+ CCNxCodecEncodingBuffer *encodingBuffer = ccnxCodecEncodingBuffer_Create();
+ ccnxCodecEncodingBuffer_AppendBuffer(encodingBuffer, name);
+ ccnxCodecEncodingBuffer_AppendBuffer(encodingBuffer, space);
+ parcBuffer_Release(&space);
+ parcBuffer_Release(&name);
+
+ CCNxCodecEncodingBuffer *emailBuffer = ccnxCodecEncodingBuffer_Create();
+ ccnxCodecEncodingBuffer_AppendBuffer(emailBuffer, email);
+ parcBuffer_Release(&email);
+
+ ccnxCodecEncodingBuffer_Release(&emailBuffer);
+
+ CCNxCodecEncodingBufferIOVec *iov = ccnxCodecEncodingBuffer_CreateIOVec(encodingBuffer);
+ ssize_t nwritten = writev(STDOUT_FILENO, iov->iov, iov->iovcnt);
+ assertTrue(nwritten > -1, "Error writev");
+
+ ccnxCodecEncodingBufferIOVec_Release(&iov);
+
+ ccnxCodecEncodingBuffer_Release(&encodingBuffer);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodec_EncodingBuffer);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_Error.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_Error.c
new file mode 100755
index 00000000..1fee88c3
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_Error.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodec_Error.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(tlv_Errors)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(tlv_Errors)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(tlv_Errors)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetByteOffset);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetErrorCode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetLine);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetFunction);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecError_GetErrorMessage);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecError_Create_Destroy)
+{
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, "apple", 10, 100);
+ ccnxCodecError_Release(&error);
+ assertTrue(parcMemory_Outstanding() == 0, "memory imbalance after create/destroy");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecError_GetByteOffset)
+{
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, "apple", 10, 100);
+ assertTrue(ccnxCodecError_GetByteOffset(error) == 100,
+ "Wrong offset, expected %u got %zu",
+ 100,
+ ccnxCodecError_GetByteOffset(error));
+ ccnxCodecError_Release(&error);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecError_GetErrorCode)
+{
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, "apple", 10, 100);
+ assertTrue(ccnxCodecError_GetErrorCode(error) == TLV_ERR_NO_ERROR,
+ "Wrong error code, expected %d got %d",
+ TLV_ERR_NO_ERROR,
+ ccnxCodecError_GetErrorCode(error));
+ ccnxCodecError_Release(&error);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecError_GetLine)
+{
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, "apple", 10, 100);
+ assertTrue(ccnxCodecError_GetLine(error) == 10,
+ "Wrong line number, expected %d got %d",
+ 10,
+ ccnxCodecError_GetLine(error));
+ ccnxCodecError_Release(&error);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecError_GetFunction)
+{
+ char *apple = "apple";
+
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, apple, 10, 100);
+ assertTrue(ccnxCodecError_GetFunction(error) == apple,
+ "Wrong function string, expected %p got %p",
+ apple,
+ ccnxCodecError_GetFunction(error));
+ ccnxCodecError_Release(&error);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecError_GetErrorMessage)
+{
+ char *apple = "apple";
+ const char *truth = ccnxCodecErrors_ErrorMessage(TLV_ERR_NO_ERROR);
+
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_NO_ERROR, apple, 10, 100);
+ assertTrue(ccnxCodecError_GetErrorMessage(error) == truth,
+ "Wrong function string, expected %p got %p",
+ truth,
+ ccnxCodecError_GetErrorMessage(error));
+ ccnxCodecError_Release(&error);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(tlv_Errors);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_NetworkBuffer.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_NetworkBuffer.c
new file mode 100755
index 00000000..aec3018e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_NetworkBuffer.c
@@ -0,0 +1,952 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodec_NetworkBuffer.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+
+typedef struct test_data {
+ CCNxCodecNetworkBuffer *buffer;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->buffer = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ ccnxCodecNetworkBuffer_Release(&data->buffer);
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(ccnx_NetworkBuffer)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(SetLimit);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_NetworkBuffer)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_NetworkBuffer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBufferIoVec_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_Acquire);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_ComputeSignature);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_Create);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_CreateFromArray);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_CreateIoVec);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_Display);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_GetUint8);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_GetUint8_NotCurrentBlock);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_Position);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpaceOk);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpaceToZero);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_NoSpace);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpanThree);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutBuffer);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint16);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint64);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_SpaceOk);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_SpaceToZero);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_NoSpace);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_OK);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_2bytes);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_2bytes_withnext);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_BeyondLimit);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_InCurrent);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_InDifferent);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNetworkbufferIoVec_GetArray);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNetworkbufferIoVec_GetCount);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNetworkbufferIoVec_Length);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNetworkbufferIoVec_Display);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBufferIoVec_Acquire)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxCodecNetworkBufferIoVec *first = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer);
+ assertTrue(first->refcount == 1, "Wrong refcount, got %u expected %u", first->refcount, 1);
+
+ CCNxCodecNetworkBufferIoVec *second = ccnxCodecNetworkBufferIoVec_Acquire(first);
+ assertTrue(first->refcount == 2, "Wrong refcount, got %u expected %u", first->refcount, 2);
+
+ ccnxCodecNetworkBufferIoVec_Release(&second);
+ ccnxCodecNetworkBufferIoVec_Release(&first);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_Acquire)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxCodecNetworkBuffer *second = ccnxCodecNetworkBuffer_Acquire(data->buffer);
+ assertTrue(data->buffer->refcount == 2, "wrong refcount, got %u expected %u", data->buffer->refcount, 2);
+ ccnxCodecNetworkBuffer_Release(&second);
+ assertTrue(data->buffer->refcount == 1, "wrong refcount, got %u expected %u", data->buffer->refcount, 1);
+}
+
+/*
+ * Uses a test set generated by openssl:
+ * openssl genrsa -out test_rsa_key.pem
+ * openssl rsa -pubout -in test_rsa_key.pem -out test_rsa_pub.pem
+ * openssl req -new -key test_rsa_key.pem -out test_rsa.csr
+ * openssl x509 -req -days 365 -in test_rsa.csr -signkey test_rsa_key.pem -out test_rsa.crt
+ * openssl pkcs12 -export -in test_rsa.crt -inkey test_rsa_key.pem -out test_rsa.p12 -name ccnxuser -CAfile test_rsa.crt -caname root -chain -passout pass:blueberry
+ * openssl sha -sha256 -sign test_rsa_key.pem -out test_random_bytes.sig < test_random_bytes
+ *
+ * In English: generate a public private key, put it in a PKCS12 file (test_rsa.p12), then use that to sign
+ * a buffer (test_random_bytes) and put the signature in a file (test_random_bytes.sig).
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_ComputeSignature)
+{
+ parcSecurity_Init();
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ parcKeyStore_Release(&keyStore);
+ assertNotNull(signer, "Got null result from opening openssl pkcs12 file");
+
+ // read the buffer to sign
+ int fd = open("test_random_bytes", O_RDONLY);
+ assertTrue(fd != -1, "Cannot open test_random_bytes file.");
+ uint8_t buffer_to_sign[2048];
+ ssize_t read_bytes = read(fd, buffer_to_sign, 2048);
+ close(fd);
+
+ // Put it in a NetworkBuffer
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, read_bytes, buffer_to_sign);
+
+ // Sign it
+ PARCSignature *testSignature = ccnxCodecNetworkBuffer_ComputeSignature(data->buffer, 0, ccnxCodecNetworkBuffer_Limit(data->buffer), signer);
+ PARCBuffer *testBytes = parcSignature_GetSignature(testSignature);
+
+ // now read the "true" signature
+ uint8_t scratch_buffer[1024];
+ fd = open("test_random_bytes.sig", O_RDONLY);
+ assertTrue(fd != -1, "Cannot open test_random_bytes.sig file.");
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes == 128, "read incorrect size signature from disk: %zu", read_bytes);
+ close(fd);
+
+ PARCBuffer *truth = parcBuffer_Wrap(scratch_buffer, read_bytes, 0, read_bytes);
+
+ assertTrue(parcBuffer_Equals(testBytes, truth), "Signatures do not match")
+ {
+ parcBuffer_Display(testBytes, 0);
+ parcBuffer_Display(truth, 0);
+ }
+
+ parcBuffer_Release(&truth);
+ parcSignature_Release(&testSignature);
+ parcSigner_Release(&signer);
+
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_Create)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertNotNull(data->buffer, "null buffer");
+ assertTrue(data->buffer->head == data->buffer->current && data->buffer->current == data->buffer->tail,
+ "wrong pointers, head should equal current should equal tail");
+ assertTrue(data->buffer->refcount == 1, "wrong refcount, got %u expected %u", data->buffer->refcount, 1);
+ assertTrue(data->buffer->position == 0, "wrong position, got %zu expected %u", data->buffer->position, 1);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_CreateFromArray)
+{
+ size_t length = 64;
+ uint8_t *memory = parcMemory_Allocate(length);
+ assertNotNull(memory, "parcMemory_Allocate(%zu) returned NULL", length);
+ for (int i = 0; i < length; i++) {
+ memory[i] = i * 3;
+ }
+
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, length, memory);
+
+ assertNotNull(netbuff, "Got null from createFromArray");
+
+ PARCBuffer *test = ccnxCodecNetworkBuffer_CreateParcBuffer(netbuff);
+ PARCBuffer *truth = parcBuffer_Wrap(memory, length, 0, length);
+
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers do not match")
+ {
+ ccnxCodecNetworkBuffer_Display(netbuff, 3);
+ parcBuffer_Display(test, 3);
+ parcBuffer_Display(truth, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_CreateIoVec)
+{
+ // Write an array that will span 3 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer);
+
+ assertTrue(vec->iovcnt == 5, "iovcnt wrong got %d expected %d", vec->iovcnt, 5);
+ assertTrue(vec->totalBytes == 8192, "Wrong total bytes, got %zu expected %u", vec->totalBytes, 8192)
+ {
+ ccnxCodecNetworkBufferIoVec_Display(vec, 3);
+ }
+
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+/*
+ * not much to do excpet make sure there's no leaks or assertions
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_Display)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_Position)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->buffer->position = 22;
+
+ size_t test = ccnxCodecNetworkBuffer_Position(data->buffer);
+ assertTrue(test == 22, "wrong position, got %zu expected %u", test, 22);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpaceOk)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t array[] = { 1, 2, 3, 4, 5, 6 };
+ size_t nextPosition = data->buffer->position + sizeof(array);
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, sizeof(array), array);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(memcmp(&data->buffer->current->memory[0], array, sizeof(array)) == 0, "wrong memory");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpaceToZero)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t array[] = { 1, 2, 3, 4, 5, 6 };
+
+ size_t startPosition = data->buffer->capacity - sizeof(array);
+ size_t nextPosition = startPosition + sizeof(array);
+
+ data->buffer->position = startPosition;
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, sizeof(array), array);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(memcmp(&data->buffer->current->memory[startPosition], array, sizeof(array)) == 0, "wrong memory");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_NoSpace)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t array[] = { 1, 2, 3, 4, 5, 6 };
+
+ // 3 elements in the current block, 3 in the next block
+ size_t startPosition = data->buffer->capacity - 3;
+ size_t nextPosition = startPosition + sizeof(array);
+
+ data->buffer->position = startPosition;
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, sizeof(array), array);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(memcmp(&data->buffer->head->memory[startPosition], array, 3) == 0, "wrong memory");
+ assertTrue(memcmp(&data->buffer->tail->memory[0], array + 3, 3) == 0, "wrong memory");
+ // and we should have a new buffer
+ assertTrue(data->buffer->head != data->buffer->tail, "head should not be equal to tail");
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutArray_SpanThree)
+{
+ // Write an array that will span 3 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+
+ CCNxCodecNetworkBufferMemory *block = data->buffer->head;
+ size_t offset = 0;
+ while (offset < arrayLength) {
+ size_t remaining = (arrayLength - offset > block->capacity) ? block->capacity : arrayLength - offset;
+ assertTrue(memcmp(&block->memory[0], array + offset, remaining) == 0, "wrong memory");
+ offset += remaining;
+ block = block->next;
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutBuffer)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t array[] = { 1, 2, 3, 4, 5, 6 };
+ PARCBuffer *buffer = parcBuffer_Wrap(array, sizeof(array), 0, sizeof(array));
+
+ size_t nextPosition = data->buffer->position + sizeof(array);
+
+ ccnxCodecNetworkBuffer_PutBuffer(data->buffer, buffer);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(memcmp(&data->buffer->current->memory[0], array, sizeof(array)) == 0, "wrong memory");
+
+ parcBuffer_Release(&buffer);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint16)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint16_t value = 0x2587;
+ size_t nextPosition = data->buffer->position + sizeof(value);
+
+ ccnxCodecNetworkBuffer_PutUint16(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+
+ uint16_t testValue = htons(value);
+ assertTrue(memcmp(&data->buffer->current->memory[0], &testValue, sizeof(testValue)) == 0, "wrong memory")
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint64)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint64_t value = 0xABCDEF0122334455;
+ size_t nextPosition = data->buffer->position + sizeof(value);
+
+ ccnxCodecNetworkBuffer_PutUint64(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+
+ uint8_t truthValue[] = { 0xAB, 0xCD, 0xEF, 0x01, 0x22, 0x33, 0x44, 0x55 };
+ assertTrue(memcmp(&data->buffer->current->memory[0], truthValue, sizeof(truthValue)) == 0, "wrong memory")
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+}
+
+/*
+ * Put a uint32 in to a block with plenty of space
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_OK)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint32_t value = 0xABCDEF01;
+ size_t nextPosition = data->buffer->position + 4;
+
+ ccnxCodecNetworkBuffer_PutUint32(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+
+ uint32_t testValue = htonl(value);
+ assertTrue(memcmp(&data->buffer->current->memory[0], &testValue, sizeof(testValue)) == 0, "wrong memory")
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+}
+
+/*
+ * The current block only has 2 bytes left and there is no next pointer. Should throw away
+ * those 2 bytes, allocate a new block, then write the whole thing there.
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_2bytes)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // set limit and position out to capacity -2
+ data->buffer->current->limit = data->buffer->current->capacity - 2;
+ data->buffer->position = data->buffer->current->limit;
+
+ uint32_t value = 0xABCDEF01;
+ size_t nextPosition = data->buffer->position + 4;
+
+ ccnxCodecNetworkBuffer_PutUint32(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+
+ uint32_t testValue = htonl(value);
+ assertTrue(memcmp(&data->buffer->current->memory[0], &testValue, sizeof(testValue)) == 0, "wrong memory")
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+}
+
+/*
+ * The current block only has 2 bytes left and there is a next block. Because the current
+ * block is frozen, it will need to split the write over the two blocks.
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint32_2bytes_withnext)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // this is where we'll want to start our write
+ size_t start = data->buffer->current->capacity - 2;
+ size_t nextPosition = start + 4;
+
+ // set limit and position out to capacity then allocate another block
+ data->buffer->current->limit = data->buffer->current->capacity;
+ data->buffer->position = data->buffer->current->limit;
+ _ccnxCodecNetworkBuffer_AllocateIfNeeded(data->buffer);
+
+ ccnxCodecNetworkBuffer_SetPosition(data->buffer, start);
+ uint32_t value = 0x33445566;
+ ccnxCodecNetworkBuffer_PutUint32(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+
+ uint32_t testValue = htonl(value);
+ // check the value is split between the two buffers
+ assertTrue(memcmp(&data->buffer->head->memory[start], &testValue, 2) == 0, "wrong memory in first buffer")
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+
+ assertTrue(memcmp(&data->buffer->tail->memory[0], (uint8_t *) &testValue + 2, 2) == 0, "wrong memory in second buffer")
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_GetUint8)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint8_t value = 1;
+
+ ccnxCodecNetworkBuffer_PutUint8(data->buffer, value);
+
+ uint8_t test = ccnxCodecNetworkBuffer_GetUint8(data->buffer, 0);
+ assertTrue(data->buffer->current->memory[0] == test, "wrong memory, got %u expected %u", test, data->buffer->current->memory[0]);
+}
+
+/*
+ * Write stuff that spans two blocks, then get the uint8 from the second block
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_GetUint8_NotCurrentBlock)
+{
+ // Write an array that will span 5 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+
+ uint8_t test = ccnxCodecNetworkBuffer_GetUint8(data->buffer, 4777);
+ assertTrue(test == array[4777], "Data at index 4777 wrong, got %02X expected %02X",
+ test, array[4777]);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_SpaceOk)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint8_t value = 1;
+ size_t relativePosition = data->buffer->position - data->buffer->current->begin;
+ size_t nextPosition = data->buffer->position + 1;
+
+ ccnxCodecNetworkBuffer_PutUint8(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(data->buffer->current->memory[relativePosition] == value, "wrong memory");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_SpaceToZero)
+{
+ // put the position to just before the end of the buffer
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint8_t value = 1;
+
+ data->buffer->position = data->buffer->current->capacity - 1;
+ size_t relativePosition = data->buffer->position - data->buffer->current->begin;
+ size_t nextPosition = data->buffer->position + 1;
+
+ ccnxCodecNetworkBuffer_PutUint8(data->buffer, value);
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(data->buffer->current->memory[relativePosition] == value, "wrong memory");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_PutUint8_NoSpace)
+{
+ // put the position at the end of the current buffer, force an allocation
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint8_t value = 1;
+
+ // pretend we've written all the way out to the capacity
+ data->buffer->position = data->buffer->current->capacity;
+ data->buffer->current->limit = data->buffer->current->capacity;
+
+ size_t nextPosition = data->buffer->position + 1;
+
+ ccnxCodecNetworkBuffer_PutUint8(data->buffer, value);
+
+ size_t relativePosition = 0;
+
+ assertTrue(data->buffer->position == nextPosition, "Wrong position, got %zu expected %zu", data->buffer->position, nextPosition);
+ assertTrue(data->buffer->current->memory[relativePosition] == value, "wrong memory");
+ // and we should have a new buffer
+ assertTrue(data->buffer->head != data->buffer->tail, "head should not be equal to tail");
+}
+
+/*
+ * Set position beyond the limit of what's been written
+ */
+LONGBOW_TEST_CASE_EXPECTS(Global, ccnxCodecNetworkBuffer_SetPosition_BeyondLimit, .event = &LongBowAssertEvent)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t limit = ccnxCodecNetworkBuffer_Limit(data->buffer);
+ ccnxCodecNetworkBuffer_SetPosition(data->buffer, limit + 1);
+}
+
+/*
+ * Set position to good location that is in the current block
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_InCurrent)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxCodecNetworkBuffer_PutUint32(data->buffer, 0x12345678);
+
+ size_t limit = ccnxCodecNetworkBuffer_Limit(data->buffer);
+ ccnxCodecNetworkBuffer_SetPosition(data->buffer, limit - 1);
+
+ assertTrue(data->buffer->current->memory[data->buffer->position] == 0x78,
+ "Wrong memory got %02X expected %02X",
+ data->buffer->current->memory[data->buffer->position], 0x78)
+ {
+ ccnxCodecNetworkBuffer_Display(data->buffer, 0);
+ }
+}
+
+/*
+ * Set position to a good location that is not in the current block
+ */
+LONGBOW_TEST_CASE(Global, ccnxCodecNetworkBuffer_SetPosition_InDifferent)
+{
+ // Write an array that will span 5 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+
+ ccnxCodecNetworkBuffer_SetPosition(data->buffer, 4777);
+
+ assertTrue(data->buffer->position == 4777, "Wrong position set, got %zu expected %u", data->buffer->position, 4777);
+ assertTrue(_ccnxCodecNetworkBufferMemory_ContainsPosition(data->buffer->current, 4777), "Did not seek to right position");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNetworkbufferIoVec_GetArray)
+{
+ // Write an array that will span 3 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer);
+
+ const struct iovec *iov = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+ assertTrue(iov == vec->array, "Got wrong iovec array, got %p expected %p", (void *) iov, (void *) vec->array);
+
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNetworkbufferIoVec_GetCount)
+{
+ // Write an array that will span 3 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer);
+
+ assertTrue(ccnxCodecNetworkBufferIoVec_GetCount(vec) == 5, "iovcnt wrong got %d expected %d", ccnxCodecNetworkBufferIoVec_GetCount(vec), 5);
+
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNetworkbufferIoVec_Length)
+{
+ // Write an array that will span 3 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer);
+
+ assertTrue(ccnxCodecNetworkBufferIoVec_Length(vec) == arrayLength, "Wrong length got %zu expected %zu", ccnxCodecNetworkBufferIoVec_Length(vec), arrayLength);
+
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNetworkbufferIoVec_Display)
+{
+ // Write an array that will span 3 blocks
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ size_t arrayLength = 8192;
+ uint8_t array[arrayLength];
+
+ // fill the array with stuff so we have a pattern that must match
+ for (size_t i = 0; i < arrayLength; i++) {
+ array[i] = i;
+ }
+
+ ccnxCodecNetworkBuffer_PutArray(data->buffer, arrayLength, array);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(data->buffer);
+
+ ccnxCodecNetworkBufferIoVec_Display(vec, 0);
+
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+// =====================================================================
+
+LONGBOW_TEST_FIXTURE(SetLimit)
+{
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_EndOfTail);
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_MidOfTail);
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_StartOfTail);
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_EndOfMid);
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_MidOfMid);
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_StartOfMid);
+ LONGBOW_RUN_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_Zero);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(SetLimit)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(SetLimit)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+typedef struct setlimit_s {
+ CCNxCodecNetworkBuffer *netbuff;
+ PARCBuffer *truth;
+} SetLimitData;
+
+/*
+ * In this test, SetLimit is called when we are at position 4036
+ *
+ * (always in ABSOLUTE bytes)
+ * position = 4077
+ * begin = 0 begin = 1536 begin = 3577 |
+ * | | | |
+ * +--------------------------+--------------------------+--------------------------+
+ * | block 0 | block 1 | block 2 |
+ * +--------------------------+--------------------------+--------------------------+
+ * | | | |
+ * capacity = 1536 capacity = 2048 | capacity = 2048
+ * limit = 1536 limit = 2041 limit = 500
+ * (always in RELATIVE bytes)
+ */
+static SetLimitData
+_allocateData(void)
+{
+ SetLimitData data;
+
+ data.netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+
+ size_t buffer1_length = 3577;
+ uint8_t buffer1[buffer1_length];
+ memset(buffer1, 0x11, buffer1_length);
+
+ ccnxCodecNetworkBuffer_PutArray(data.netbuff, buffer1_length, buffer1);
+ assertTrue(data.netbuff->position == buffer1_length, "Wrong position, expected %zu got %zu", buffer1_length, data.netbuff->position);
+
+ // we should be in 'block1' in the diagram
+ assertTrue(data.netbuff->current->limit == 2041, "wrong limit, expected %u got %zu", 2041, data.netbuff->current->limit);
+
+ // now allocate the second buffer to move to 'block 2'. this should freeze 'block 1' at 2000 bytes.
+
+ // now we need to write it at 8 bytes to get block 1 to freeze
+ uint64_t x = 0x1234567812345678ULL;
+
+ ccnxCodecNetworkBuffer_PutUint64(data.netbuff, x);
+ assertTrue(data.netbuff->position == 3585, "Wrong position, expected %u got %zu", 3585, data.netbuff->position);
+ assertTrue(data.netbuff->current->limit == 8, "wrong limit, expected %u got %zu", 8, data.netbuff->current->limit);
+
+ size_t buffer2_length = 492;
+ uint8_t buffer2[buffer2_length];
+ memset(buffer2, 0xaa, buffer2_length);
+
+ ccnxCodecNetworkBuffer_PutArray(data.netbuff, buffer2_length, buffer2);
+
+ assertTrue(data.netbuff->position == 4077, "Wrong position, expected %u got %zu", 4077, data.netbuff->current->limit);
+ assertTrue(data.netbuff->current->limit == 500, "wrong limit, expected %u got %zu", 500, data.netbuff->current->limit);
+
+ data.truth = parcBuffer_Allocate(buffer1_length + buffer2_length + 8);
+ parcBuffer_PutArray(data.truth, buffer1_length, buffer1);
+ parcBuffer_PutUint64(data.truth, x);
+ parcBuffer_PutArray(data.truth, buffer2_length, buffer2);
+ parcBuffer_Flip(data.truth);
+
+ return data;
+}
+
+static void
+_destroyData(SetLimitData data)
+{
+ ccnxCodecNetworkBuffer_Release(&data.netbuff);
+ parcBuffer_Release(&data.truth);
+}
+
+static void
+_runDataTest(size_t position)
+{
+ SetLimitData data = _allocateData();
+ ccnxCodecNetworkBuffer_SetPosition(data.netbuff, position);
+ parcBuffer_SetLimit(data.truth, position);
+
+ ccnxCodecNetworkBuffer_Finalize(data.netbuff);
+ PARCBuffer *test = ccnxCodecNetworkBuffer_CreateParcBuffer(data.netbuff);
+ assertTrue(parcBuffer_Equals(data.truth, test), "wrong value")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(data.truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ _destroyData(data);
+}
+
+/*
+ * In this test, SetLimit is called when we are at position 4077
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_EndOfTail)
+{
+ _runDataTest(4077);
+}
+
+/*
+ * In this test, SetLimit is called when we are at position 4000, which
+ * is in the middle of 'block 2'
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_MidOfTail)
+{
+ _runDataTest(4000);
+}
+
+/*
+ * In this test, SetLimit is called when we are at position 3577, which
+ * is in the start of 'block 2'
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_StartOfTail)
+{
+ _runDataTest(3577);
+}
+
+/*
+ * In this test, SetLimit is called when we are at position 3576, which
+ * is the last byte of 'block 1'
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_EndOfMid)
+{
+ _runDataTest(3576);
+}
+
+/*
+ * In this test, SetLimit is called when we are at position 2000, which
+ * is the middle of 'block 1'
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_MidOfMid)
+{
+ _runDataTest(2000);
+}
+
+/*
+ * 1536 is 1st byte of 'block 1'
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_StartOfMid)
+{
+ _runDataTest(1536);
+}
+
+/*
+ * Wipe it all out
+ */
+LONGBOW_TEST_CASE(SetLimit, ccnxCodecNetworkBuffer_Finalize_Zero)
+{
+ _runDataTest(0);
+}
+
+
+// =========================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _ccnxCodecNetworkBufferMemory_Allocate);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _ccnxCodecNetworkBufferMemory_Allocate)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ size_t desired = 2048;
+ CCNxCodecNetworkBufferMemory *memory = _ccnxCodecNetworkBufferMemory_Allocate(data->buffer, desired);
+ assertNotNull(memory, "Got null memory");
+ assertNull(memory->next, "memory->next is not null");
+ assertTrue(memory->begin == 0, "memory has wrong offset, got %zu expecting %u", memory->begin, 0);
+ assertTrue(memory->capacity == desired, "Wrong capacity, got %zu expecting %zu", memory->capacity, desired);
+
+ _ccnxCodecNetworkBufferMemory_Release(data->buffer, &memory);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_NetworkBuffer);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvDecoder.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvDecoder.c
new file mode 100755
index 00000000..db835bb5
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvDecoder.c
@@ -0,0 +1,808 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodec_TlvDecoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <inttypes.h>
+
+LONGBOW_TEST_RUNNER(parc_Tlv)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Decoder);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Tlv)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Tlv)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ============================================
+
+LONGBOW_TEST_FIXTURE(Decoder)
+{
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Create);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetLength);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_PeekType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetValue);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetValue_TooLong);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetContainer);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetContainer_TooLong);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_IsEmpty_True);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_IsEmpty_False);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Position);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_EnsureRemaining_True);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_EnsureRemaining_False);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_Good);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_Short);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_WrongType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_WrongLength);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_Good);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_Short);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_WrongType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_WrongLength);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_Good);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_Short);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_WrongType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_WrongLength);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_Good);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_Short);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_WrongType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_WrongLength);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_Good);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_WrongType);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_TooShort);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_TooLong);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Advance_Good);
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Advance_TooLong);
+
+ LONGBOW_RUN_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetVarInt);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Decoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Decoder)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/**
+ * check for memory leaks on create/destroy
+ */
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Create)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ size_t before = parcMemory_Outstanding();
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ size_t after = parcMemory_Outstanding();
+ parcBuffer_Release(&buffer);
+ assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetLength)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ // we're calling this on byte 0, so the "length" will be 0x0001
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(outerDecoder);
+
+ assertTrue(parcBuffer_Position(outerDecoder->buffer) == 2,
+ "Did not advance buffer to right spot, expected %u got %zu",
+ 2, parcBuffer_Position(outerDecoder->buffer));
+
+ assertTrue(length == 1, "Wrong length expected %u got %u", 1, length);
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetType)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ uint16_t type = ccnxCodecTlvDecoder_GetType(outerDecoder);
+
+ assertTrue(parcBuffer_Position(outerDecoder->buffer) == 2,
+ "Did not advance buffer to right spot, expected %u got %zu",
+ 2, parcBuffer_Position(outerDecoder->buffer));
+
+ assertTrue(type == 1, "Wrong type expected %u got %u", 1, type);
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_PeekType)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ uint16_t type = ccnxCodecTlvDecoder_PeekType(outerDecoder);
+
+ assertTrue(parcBuffer_Position(outerDecoder->buffer) == 0,
+ "Did not advance buffer to right spot, expected %u got %zu",
+ 0, parcBuffer_Position(outerDecoder->buffer));
+
+ assertTrue(type == 1, "Wrong type expected %u got %u", 1, type);
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetValue)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ uint16_t type = ccnxCodecTlvDecoder_GetType(outerDecoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(outerDecoder);
+
+ assertTrue(type == 1, "Wrong type expected %u got %u", 1, type);
+ assertTrue(length == 19, "Wrong length expected %u got %u", 19, length);
+
+ PARCBuffer *inner = ccnxCodecTlvDecoder_GetValue(outerDecoder, length);
+
+ // inner should now be empty
+ assertTrue(ccnxCodecTlvDecoder_IsEmpty(outerDecoder), "outer decoder should be emtpy");
+
+ CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_Create(inner);
+ parcBuffer_Release(&inner);
+
+ type = ccnxCodecTlvDecoder_GetType(innerDecoder);
+ length = ccnxCodecTlvDecoder_GetLength(innerDecoder);
+
+ assertTrue(type == 2, "Wrong type expected %u got %u", 2, type);
+ assertTrue(length == 5, "Wrong length expected %u got %u", 5, length);
+
+ PARCBuffer *hello = ccnxCodecTlvDecoder_GetValue(innerDecoder, length);
+
+ parcBuffer_Release(&hello);
+ ccnxCodecTlvDecoder_Destroy(&innerDecoder);
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetValue_TooLong)
+{
+ // Length is beyond end of buffer
+ uint8_t truthBytes[] = { 0x00, 0x02, 0x00, 0x99, 'h', 'e', 'l', 'l', 'o' };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ (void) ccnxCodecTlvDecoder_GetType(outerDecoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(outerDecoder);
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(outerDecoder, length);
+
+ assertNull(value, "Value should be null because of buffer underrun");
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_IsEmpty_True)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(outerDecoder, sizeof(truthBytes));
+ parcBuffer_Release(&value);
+
+ assertTrue(ccnxCodecTlvDecoder_IsEmpty(outerDecoder), "Decoder said it was not empty when its should be empty");
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_IsEmpty_False)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ assertFalse(ccnxCodecTlvDecoder_IsEmpty(outerDecoder), "Decoder said it was empty when its full");
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Position)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(outerDecoder, 8);
+ parcBuffer_Release(&value);
+
+ assertTrue(ccnxCodecTlvDecoder_Position(outerDecoder) == 8,
+ "Decoder reports wrong position, expected %u got %zu",
+ 8,
+ ccnxCodecTlvDecoder_Position(outerDecoder));
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_EnsureRemaining_True)
+{
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ bool success = ccnxCodecTlvDecoder_EnsureRemaining(outerDecoder, 5);
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+
+ assertTrue(success,
+ "Decoder failed ensureRemaining check for 5 bytes when its a 19 byte buffer");
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_EnsureRemaining_False)
+{
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ bool success = ccnxCodecTlvDecoder_EnsureRemaining(outerDecoder, 24);
+
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+
+ assertFalse(success,
+ "Decoder passed ensureRemaining check for 24 bytes when its a 19 byte buffer");
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_Good)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x01, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint8_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value);
+ assertTrue(success, "Did not decode a correct buffer");
+ assertTrue(value == 0xFF, "Incorrect value, expected 0x%X got 0x%X", 0xFF, value);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_Short)
+{
+ // LIMIT IS SHORT
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x01, 0xFF }, 5, 0, 4);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint8_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value);
+ assertFalse(success, "Should have failed a short buffer");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_WrongType)
+{
+ // TYPE IS WRONG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x01, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint8_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint8_WrongLength)
+{
+ // LENGTH TOO BIG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x99, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint8_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint8(decoder, 0x1020, &value);
+ assertFalse(success, "Should have failed because of incorrect length");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_Good)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x02, 0xFF, 0x01 }, 6, 0, 6);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint16_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value);
+ assertTrue(success, "Did not decode a correct buffer");
+ assertTrue(value == 0xFF01, "Incorrect value, expected 0x%X got 0x%X", 0xFF01, value);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_Short)
+{
+ // LIMIT IS SHORT
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x02, 0xFF, 0x01 }, 6, 0, 5);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint16_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_WrongType)
+{
+ // TYPE IS WRONG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x02, 0xFF, 0x01 }, 6, 0, 6);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint16_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint16_WrongLength)
+{
+ // LENGTH TOO BIG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x99, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint16_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint16(decoder, 0x1021, &value);
+ assertFalse(success, "Should have failed because of incorrect length");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_Good)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint32_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value);
+ assertTrue(success, "Did not decode a correct buffer");
+ assertTrue(value == 0xFF010203, "Incorrect value, expected 0x%X got 0x%X", 0xFF010203, value);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_Short)
+{
+ // LIMIT IS SHORT
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 7);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint32_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_WrongType)
+{
+ // TYPE IS WRONG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint32_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint32_WrongLength)
+{
+ // LENGTH TOO BIG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x99, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint32_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint32(decoder, 0x1022, &value);
+ assertFalse(success, "Should have failed because of incorrect length");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_Good)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 12);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint64_t value;
+ uint64_t truth = 0xFF01020304050607ULL;
+ bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value);
+ assertTrue(success, "Did not decode a correct buffer");
+ assertTrue(value == truth, "Incorrect value, expected %#" PRIx64 " got %#" PRIx64, truth, value);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_Short)
+{
+ // LIMIT IS SHORT
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 11);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint64_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_WrongType)
+{
+ // TYPE IS WRONG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x08, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 11);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint64_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value);
+ assertFalse(success, "Should have failed because of wrong type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetUint64_WrongLength)
+{
+ // LENGTH TOO BIG
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x99, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 12);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ uint64_t value;
+ bool success = ccnxCodecTlvDecoder_GetUint64(decoder, 0x1023, &value);
+ assertFalse(success, "Should have failed because of incorrect length");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_Good)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x01, 0x02, 0x03, 0x04 }, 4, 0, 4);
+ PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) { 0x00, 0x01, 0x00, 0x08, 0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04 }, 12, 0, 12);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ (void) ccnxCodecTlvDecoder_GetLength(decoder);
+
+ PARCBuffer *test = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB);
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+
+ parcBuffer_Release(&test);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&input);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_WrongType)
+{
+ // INNER TYPE IS WRONG
+ PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) { 0x00, 0x01, 0x00, 0x08, 0xFF, 0xFF, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04 }, 12, 0, 12);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ (void) ccnxCodecTlvDecoder_GetLength(decoder);
+
+ PARCBuffer *test = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB);
+ assertNull(test, "Should have returned NULL because of incorrect TLV type");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&input);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_TooShort)
+{
+ // OVERALL LENGTH TOO SHORT TO PARSE
+ // buffer only goes to here ---------------------------------!
+ PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) { 0x00, 0x01, 0x00, 0x08, 0xAA, 0xBB, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04 }, 12, 0, 6);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ (void) ccnxCodecTlvDecoder_GetLength(decoder);
+
+ PARCBuffer *test = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB);
+ assertNull(test, "Should have returned NULL because of input underrun");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&input);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetBuffer_TooLong)
+{
+ // VALUE (4 bytes) SHORTER THAN LENGTH (0x99)
+ PARCBuffer *input = parcBuffer_Wrap((uint8_t[]) { 0x00, 0x01, 0x00, 0x08, 0xAA, 0xBB, 0x00, 0x99, 0x01, 0x02, 0x03, 0x04 }, 12, 0, 12);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(input);
+
+ (void) ccnxCodecTlvDecoder_GetType(decoder);
+ (void) ccnxCodecTlvDecoder_GetLength(decoder);
+
+ PARCBuffer *test = ccnxCodecTlvDecoder_GetBuffer(decoder, 0xAABB);
+ assertNull(test, "Should have returned NULL because of value underrun");
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&input);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetContainer)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ (void) ccnxCodecTlvDecoder_GetType(outerDecoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(outerDecoder);
+ CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_GetContainer(outerDecoder, length);
+ assertNotNull(innerDecoder, "Got a null decoder for a valid slice");
+ assertTrue(ccnxCodecTlvDecoder_Position(innerDecoder) == 0, "Wrong position, expected 0 got %zu", ccnxCodecTlvDecoder_Position(innerDecoder));
+ assertTrue(ccnxCodecTlvDecoder_EnsureRemaining(innerDecoder, 19), "Inner decoder does not have enough bytes in it");
+
+ ccnxCodecTlvDecoder_Destroy(&innerDecoder);
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetContainer_TooLong)
+{
+ /**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+ uint8_t truthBytes[] = {
+ 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v'
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ CCNxCodecTlvDecoder *outerDecoder = ccnxCodecTlvDecoder_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ (void) ccnxCodecTlvDecoder_GetType(outerDecoder);
+ (void) ccnxCodecTlvDecoder_GetLength(outerDecoder);
+ // ask for too many bytes
+ CCNxCodecTlvDecoder *innerDecoder = ccnxCodecTlvDecoder_GetContainer(outerDecoder, 100);
+ assertNull(innerDecoder, "Got a decoder for an invalid slice");
+ ccnxCodecTlvDecoder_Destroy(&outerDecoder);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Advance_Good)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+
+ size_t advance = 3;
+ size_t beforePosition = ccnxCodecTlvDecoder_Position(decoder);
+ bool success = ccnxCodecTlvDecoder_Advance(decoder, advance);
+ size_t afterPosition = ccnxCodecTlvDecoder_Position(decoder);
+
+ assertTrue(success, "Failed to advance decoder");
+ assertTrue(beforePosition + advance == afterPosition, "Wrong position, got %zu expected %zu", afterPosition, beforePosition + advance);
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_Advance_TooLong)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((uint8_t[]) { 0xFF, 0xFF, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+
+ size_t advance = 9;
+ size_t beforePosition = ccnxCodecTlvDecoder_Position(decoder);
+ bool success = ccnxCodecTlvDecoder_Advance(decoder, advance);
+ size_t afterPosition = ccnxCodecTlvDecoder_Position(decoder);
+
+ assertFalse(success, "Should have returned false advancing beyond end of decoder");
+ assertTrue(beforePosition == afterPosition, "Wrong position, got %zu expected %zu", afterPosition, beforePosition);
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Decoder, ccnxCodecTlvDecoder_GetVarInt)
+{
+ struct test_vector {
+ uint64_t value;
+ bool valid;
+ int length;
+ uint8_t *array;
+ } vectors[] = {
+ // length 0 invalid
+ { .value = 0, .valid = false, .length = 0, .array = (uint8_t[]) { 0x00 } },
+ { .value = 0, .valid = true, .length = 1, .array = (uint8_t[]) { 0x00 } },
+ { .value = 0xFF, .valid = true, .length = 1, .array = (uint8_t[]) { 0xFF } },
+ { .value = 0x0001, .valid = true, .length = 2, .array = (uint8_t[]) { 0x00, 0x01} },
+ { .value = 0xFF01, .valid = true, .length = 2, .array = (uint8_t[]) { 0xFF, 0x01} },
+ { .value = 0x000001, .valid = true, .length = 3, .array = (uint8_t[]) { 0x00, 0x00, 0x01} },
+ { .value = 0xFF0001, .valid = true, .length = 3, .array = (uint8_t[]) { 0xFF, 0x00, 0x01} },
+ { .value = 0x00000001, .valid = true, .length = 4, .array = (uint8_t[]) { 0x00, 0x00, 0x00, 0x01} },
+ { .value = 0xFF002001, .valid = true, .length = 4, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01} },
+ { .value = 0xFF00200103040506ULL, .valid = true, .length = 8, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06} },
+ // length 9 invalid
+ { .value = 0, .valid = false, .length = 9, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06, 0x07} },
+ // sentinal is NULL array
+ { .value = 0, .valid = false, .length = 0, .array = NULL },
+ };
+
+ for (int i = 0; vectors[i].array != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_Wrap(vectors[i].array, vectors[i].length, 0, vectors[i].length);
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+
+ uint64_t value;
+ bool success = ccnxCodecTlvDecoder_GetVarInt(decoder, vectors[i].length, &value);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+
+ assertTrue(success == vectors[i].valid, "index %d: Wrong return, got %d expected %d", i, success, vectors[i].valid);
+ if (vectors[i].valid) {
+ assertTrue(value == vectors[i].value, "index %d: wrong value: got %" PRIu64 " expected %" PRIu64, i, value, vectors[i].value);
+ }
+ }
+}
+
+// ============================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Tlv);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvEncoder.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvEncoder.c
new file mode 100755
index 00000000..0898077d
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvEncoder.c
@@ -0,0 +1,874 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodec_TlvEncoder.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/validation/ccnxValidation_CRC32C.h>
+
+LONGBOW_TEST_RUNNER(parc_Tlv)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Encoder);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Tlv)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Tlv)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ==========================================
+
+LONGBOW_TEST_FIXTURE(Encoder)
+{
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendArray);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendRawArray);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendBuffer);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendBuffer_TestReturn);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendContainer);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint8);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint16);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint32);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint64);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendVarInt);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_PutUint8);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_PutUint16);
+
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Create);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize_TrimLimit_Buffer);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize_TrimLimit_IoVec);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Initialize);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Initialize_Twice);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Position);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetContainerLength);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetPosition);
+
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetError_Present);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetError_Missing);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_GetError);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ClearError_Present);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ClearError_Missing);
+
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_MarkSignatureEnd);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_MarkSignatureStart);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ComputeSignature);
+ LONGBOW_RUN_TEST_CASE(Encoder, ccnxCodecTlvEncoder_GetSigner);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Encoder)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Encoder)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendArray)
+{
+ uint8_t truthBytes[] = { 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' };
+
+ PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ uint8_t helloString[] = "hello";
+ uint8_t mrTlvString[] = "mr tlv";
+
+ CCNxCodecTlvEncoder *innerEncoder = ccnxCodecTlvEncoder_Create();
+
+ // sizeof -1 to account for null byte at end of string
+ ccnxCodecTlvEncoder_AppendArray(innerEncoder, 2, sizeof(helloString) - 1, helloString);
+ ccnxCodecTlvEncoder_AppendArray(innerEncoder, 3, sizeof(mrTlvString) - 1, mrTlvString);
+
+ ccnxCodecTlvEncoder_Finalize(innerEncoder);
+ PARCBuffer *inner = ccnxCodecTlvEncoder_CreateBuffer(innerEncoder);
+
+ CCNxCodecTlvEncoder *outerEncoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_AppendBuffer(outerEncoder, 1, inner);
+ ccnxCodecTlvEncoder_Finalize(outerEncoder);
+ PARCBuffer *container = ccnxCodecTlvEncoder_CreateBuffer(outerEncoder);
+
+ parcBuffer_Release(&inner);
+
+ ccnxCodecTlvEncoder_Destroy(&innerEncoder);
+ ccnxCodecTlvEncoder_Destroy(&outerEncoder);
+
+ // parcBuffer_ToString() will not work well as we have 0 bytes, use parcBuffer_ToHexString() case 1017
+ assertTrue(parcBuffer_Equals(truth, container), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(container, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&container);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendRawArray)
+{
+ uint8_t truthBytes[] = { 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' };
+
+ PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ uint8_t helloString[] = "hello";
+ uint8_t mrTlvString[] = "mr tlv";
+
+ CCNxCodecTlvEncoder *innerEncoder = ccnxCodecTlvEncoder_Create();
+
+ // sizeof -1 to account for null byte at end of string
+ ccnxCodecTlvEncoder_AppendContainer(innerEncoder, 2, sizeof(helloString) - 1);
+ ccnxCodecTlvEncoder_AppendRawArray(innerEncoder, sizeof(helloString) - 1, helloString);
+ ccnxCodecTlvEncoder_AppendContainer(innerEncoder, 3, sizeof(mrTlvString) - 1);
+ ccnxCodecTlvEncoder_AppendRawArray(innerEncoder, sizeof(mrTlvString) - 1, mrTlvString);
+
+ ccnxCodecTlvEncoder_Finalize(innerEncoder);
+ PARCBuffer *inner = ccnxCodecTlvEncoder_CreateBuffer(innerEncoder);
+
+ CCNxCodecTlvEncoder *outerEncoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_AppendBuffer(outerEncoder, 1, inner);
+ ccnxCodecTlvEncoder_Finalize(outerEncoder);
+ PARCBuffer *container = ccnxCodecTlvEncoder_CreateBuffer(outerEncoder);
+
+ parcBuffer_Release(&inner);
+
+ ccnxCodecTlvEncoder_Destroy(&innerEncoder);
+ ccnxCodecTlvEncoder_Destroy(&outerEncoder);
+
+ // parcBuffer_ToString() will not work well as we have 0 bytes, use parcBuffer_ToHexString() case 1017
+ assertTrue(parcBuffer_Equals(truth, container), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(container, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&container);
+}
+
+
+/**
+ * We will create a TLV structure that looks like this:
+ * { T = 1, L = 19 },
+ * { T = 2, L = 5, V = "hello" }
+ * { T = 3, L = 6, V = "mr tlv" }
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendBuffer)
+{
+ uint8_t truthBytes[] = { 0x00, 0x01, 0x00, 0x13,
+ 0x00, 0x02, 0x00, 0x05,'h', 'e', 'l', 'l', 'o',
+ 0x00, 0x03, 0x00, 0x06,'m', 'r', ' ', 't', 'l', 'v' };
+
+ PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes));
+
+ uint8_t helloString[] = "hello";
+ PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5);
+
+ uint8_t mrTlvString[] = "mr tlv";
+ PARCBuffer *mrTlv = parcBuffer_Wrap(mrTlvString, 6, 0, 6);
+
+ CCNxCodecTlvEncoder *innerEncoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_AppendBuffer(innerEncoder, 2, hello);
+ ccnxCodecTlvEncoder_AppendBuffer(innerEncoder, 3, mrTlv);
+
+ ccnxCodecTlvEncoder_Finalize(innerEncoder);
+ PARCBuffer *inner = ccnxCodecTlvEncoder_CreateBuffer(innerEncoder);
+
+ CCNxCodecTlvEncoder *outerEncoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_AppendBuffer(outerEncoder, 1, inner);
+ ccnxCodecTlvEncoder_Finalize(outerEncoder);
+ PARCBuffer *container = ccnxCodecTlvEncoder_CreateBuffer(outerEncoder);
+
+ parcBuffer_Release(&inner);
+ parcBuffer_Release(&hello);
+ parcBuffer_Release(&mrTlv);
+
+ ccnxCodecTlvEncoder_Destroy(&innerEncoder);
+ ccnxCodecTlvEncoder_Destroy(&outerEncoder);
+
+ // parcBuffer_ToString() will not work well as we have 0 bytes, use parcBuffer_ToHexString() case 1017
+ assertTrue(parcBuffer_Equals(truth, container),
+ "buffers not equal\nexpected '%s'\ngot '%s'\n",
+ parcBuffer_ToString(truth),
+ parcBuffer_ToString(container)
+ );
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&container);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendBuffer_TestReturn)
+{
+ uint8_t helloString[] = "hello";
+ PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ size_t trueLength = 2 + 2 + 5;
+ size_t length = ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello);
+ assertTrue(length == trueLength, "AppendBuffer returned wrong length, expected %zu got %zu", trueLength, length);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&hello);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendContainer)
+{
+ uint8_t truthString[] = { 0x00, 0x02, 0xF1, 0x07 };
+ PARCBuffer *truth = parcBuffer_Wrap(truthString, 4, 0, 4);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ size_t trueLength = 2 + 2;
+ size_t length = ccnxCodecTlvEncoder_AppendContainer(encoder, 2, 0xF107);
+ assertTrue(length == trueLength, "AppendBuffer returned wrong length, expected %zu got %zu", trueLength, length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ assertTrue(parcBuffer_Equals(test, truth), "Buffer is incorrect.");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+}
+
+/**
+ * Check for memory leaks and correct isInitialized state
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Create)
+{
+ size_t before = parcMemory_Outstanding();
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ // add a signer to make sure it is destroyed
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+ parcSigner_Release(&signer);
+
+ // add an error to make sure its destroyed too
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1);
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ size_t after = parcMemory_Outstanding();
+ assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after);
+}
+
+/**
+ * Check for memory leaks
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize)
+{
+ size_t before = parcMemory_Outstanding();
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ parcBuffer_Release(&test);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ size_t after = parcMemory_Outstanding();
+ assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after);
+}
+
+/*
+ * Do a long write, then backup the position.
+ * After Finalize, the Limit should have trimmed off the erased part.
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize_TrimLimit_Buffer)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ uint8_t array[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ ccnxCodecTlvEncoder_AppendRawArray(encoder, sizeof(array), array);
+ ccnxCodecTlvEncoder_SetPosition(encoder, 3);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ assertTrue(parcBuffer_Remaining(test) == 3, "Wrong length, expected 3 got %zu", parcBuffer_Remaining(test));
+
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+/*
+ * Do a long write, then backup the position.
+ * After Finalize, the Limit should have trimmed off the erased part.
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Finalize_TrimLimit_IoVec)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ uint8_t array[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ ccnxCodecTlvEncoder_AppendRawArray(encoder, sizeof(array), array);
+ ccnxCodecTlvEncoder_SetPosition(encoder, 3);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+
+ CCNxCodecNetworkBufferIoVec *iov = ccnxCodecTlvEncoder_CreateIoVec(encoder);
+ assertTrue(ccnxCodecNetworkBufferIoVec_Length(iov) == 3, "Wrong length, expected 3 got %zu", ccnxCodecNetworkBufferIoVec_Length(iov));
+
+ ccnxCodecNetworkBufferIoVec_Release(&iov);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+/**
+ * Check for memory leaks and correct isInitialized state
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Initialize)
+{
+ size_t before = parcMemory_Outstanding();
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+
+ size_t after = parcMemory_Outstanding();
+ assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after);
+}
+
+/**
+ * Make sure calling Initialized on an Initialized buffer does not leak
+ */
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Initialize_Twice)
+{
+ size_t before = parcMemory_Outstanding();
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+
+ size_t after = parcMemory_Outstanding();
+ assertTrue(before == after, "Memory leak, expected %zu got %zu bytes\n", before, after);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_Position)
+{
+ uint8_t helloString[] = "hello";
+ PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ size_t length = ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello);
+ size_t position = ccnxCodecTlvEncoder_Position(encoder);
+
+ assertTrue(length == position, "Position not right expected %zu got %zu", length, position);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&hello);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetContainerLength)
+{
+ uint8_t helloString[] = "hello";
+ PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ size_t containerPosition = ccnxCodecTlvEncoder_Position(encoder);
+ ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello);
+ ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello);
+
+ size_t currentPosition = ccnxCodecTlvEncoder_Position(encoder);
+
+ // when I set the length of the first container, we should be positioned back to
+ // the current location.
+
+ ccnxCodecTlvEncoder_SetContainerLength(encoder, containerPosition, 99);
+ size_t testPosition = ccnxCodecTlvEncoder_Position(encoder);
+
+ assertTrue(testPosition == currentPosition, "Position not right expected %zu got %zu", currentPosition, testPosition);
+
+ // and make sure the length was updated
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *output = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+ parcBuffer_SetPosition(output, 2);
+ uint16_t testlength = parcBuffer_GetUint16(output);
+
+ assertTrue(testlength == 99, "Updated length wrong, expected %u got %u", 99, testlength);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&hello);
+ parcBuffer_Release(&output);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint8)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x20, 0x00, 0x01, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint16)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x21, 0x00, 0x02, 0xFF, 0x01 }, 6, 0, 6);
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint16(encoder, 0x1021, 0xFF01);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint32)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x22, 0x00, 0x04, 0xFF, 0x01, 0x02, 0x03 }, 8, 0, 8);
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint32(encoder, 0x1022, 0xFF010203);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendUint64)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, 12, 0, 12);
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint64(encoder, 0x1023, 0xFF01020304050607ULL);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_AppendVarInt)
+{
+ struct test_vector {
+ uint64_t value;
+ bool valid;
+ int length;
+ uint8_t *array;
+ } vectors[] = {
+ { .value = 0, .valid = true, .length = 5, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x01, 0x00 } },
+ { .value = 0xFF, .valid = true, .length = 5, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x01, 0xFF } },
+ { .value = 0x0101, .valid = true, .length = 6, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x02, 0x01, 0x01} },
+ { .value = 0xFF01, .valid = true, .length = 6, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x02, 0xFF, 0x01} },
+ { .value = 0x010001, .valid = true, .length = 7, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x03, 0x01, 0x00, 0x01} },
+ { .value = 0xFF0001, .valid = true, .length = 7, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x03, 0xFF, 0x00, 0x01} },
+ { .value = 0x01000000, .valid = true, .length = 8, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00} },
+ { .value = 0xFF002001, .valid = true, .length = 8, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x04, 0xFF, 0x00, 0x20, 0x01} },
+ { .value = 0xFF00200103040506ULL, .valid = true, .length = 12, .array = (uint8_t[]) { 0x10, 0x23, 0x00, 0x08, 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06} },
+ // sentinal is NULL array
+ { .value = 0, .valid = false, .length = 0, .array = NULL },
+ };
+
+ for (int i = 0; vectors[i].array != NULL; i++) {
+ // only do the valid ones for the encode test
+ if (vectors[i].valid) {
+ PARCBuffer *truth = parcBuffer_Wrap(vectors[i].array, vectors[i].length, 0, vectors[i].length);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ size_t length = ccnxCodecTlvEncoder_AppendVarInt(encoder, 0x1023, vectors[i].value);
+
+ assertTrue(length == vectors[i].length, "Wrong length index %d, got %zu expected %d", i, length, vectors[i].length);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal index %d", i)
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+ }
+ }
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_MarkSignatureEnd)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF);
+
+ ccnxCodecTlvEncoder_MarkSignatureEnd(encoder);
+ assertTrue(encoder->signatureEnd == 5, "Wrong end position, expected %u got %zu", 5, encoder->signatureEnd)
+ {
+ ccnxCodecNetworkBuffer_Display(encoder->buffer, 3);
+ }
+
+ assertTrue(encoder->signatureStartEndSet == END_SET, "Wrong flag, expected %d got %d", END_SET, encoder->signatureStartEndSet);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_MarkSignatureStart)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF);
+
+ ccnxCodecTlvEncoder_MarkSignatureStart(encoder);
+ assertTrue(encoder->signatureStart == 5, "Wrong start position, expected %u got %zu", 5, encoder->signatureStart)
+ {
+ ccnxCodecNetworkBuffer_Display(encoder->buffer, 3);
+ }
+
+ assertTrue(encoder->signatureStartEndSet == START_SET, "Wrong flag, expected %d got %d", START_SET, encoder->signatureStartEndSet);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ComputeSignature)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_MarkSignatureStart(encoder);
+ ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF);
+ ccnxCodecTlvEncoder_MarkSignatureEnd(encoder);
+
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+ parcSigner_Release(&signer);
+
+ assertTrue(encoder->signatureStartEndSet == BOTH_SET, "Wrong flag, expected %d got %d", BOTH_SET, encoder->signatureStartEndSet);
+
+ PARCSignature *sig = ccnxCodecTlvEncoder_ComputeSignature(encoder);
+ assertNotNull(sig, "Got null signature");
+
+ uint8_t truesig[] = { 0xA3, 0xAA, 0xC8, 0x4B };
+ PARCBuffer *truesigBuffer = parcBuffer_Rewind(parcBuffer_CreateFromArray(truesig, sizeof(truesig)));
+ PARCBuffer *test = parcSignature_GetSignature(sig);
+ assertTrue(parcBuffer_Equals(truesigBuffer, test), "wrong crc value")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truesigBuffer, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&truesigBuffer);
+ parcSignature_Release(&sig);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_GetSigner)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ ccnxCodecTlvEncoder_SetSigner(encoder, signer);
+
+ PARCSigner *test = ccnxCodecTlvEncoder_GetSigner(encoder);
+ assertTrue(test == signer, "Did not return the right signer, expected %p got %p", (void *) signer, (void *) test);
+ parcSigner_Release(&signer);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_PutUint8)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0xEE, 0x00, 0x01, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF);
+
+ ccnxCodecTlvEncoder_PutUint8(encoder, 1, 0xEE);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_PutUint16)
+{
+ PARCBuffer *truth = parcBuffer_Wrap((uint8_t[]) { 0x10, 0xEE, 0xDD, 0x01, 0xFF }, 5, 0, 5);
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+ ccnxCodecTlvEncoder_AppendUint8(encoder, 0x1020, 0xFF);
+
+ ccnxCodecTlvEncoder_PutUint16(encoder, 1, 0xEEDD);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ if (!parcBuffer_Equals(truth, test)) {
+ printf("Buffers not equal\n");
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ assertTrue(parcBuffer_Equals(truth, test), "Buffers not equal");
+ }
+ parcBuffer_Release(&test);
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&truth);
+}
+
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetPosition)
+{
+ uint8_t helloString[] = "hello";
+ PARCBuffer *hello = parcBuffer_Wrap(helloString, 5, 0, 5);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvEncoder_Initialize(encoder);
+
+ ccnxCodecTlvEncoder_AppendBuffer(encoder, 2, hello);
+ // position is now at 9 (2+2+5)
+
+ ccnxCodecTlvEncoder_SetPosition(encoder, 2);
+
+ size_t position = ccnxCodecTlvEncoder_Position(encoder);
+
+ assertTrue(2 == position, "Position not right expected %u got %zu", 2, position);
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&hello);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetError_Present)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1);
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+
+ // now try to set a second time
+ bool success = ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+
+
+ assertFalse(success, "Returned success when should have failed");
+ assertNotNull(encoder->error, "Encoder has null error member");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_SetError_Missing)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1);
+ bool success = ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+
+ assertTrue(success, "Returned failure when should have succeeded");
+ assertNotNull(encoder->error, "Encoder has null error member");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_GetError)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1);
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+
+ CCNxCodecError *test = ccnxCodecTlvEncoder_GetError(encoder);
+ assertNotNull(test, "Encoder has null error member");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ClearError_Present)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, "foo", 1, 1);
+ ccnxCodecTlvEncoder_SetError(encoder, error);
+ ccnxCodecError_Release(&error);
+
+ ccnxCodecTlvEncoder_ClearError(encoder);
+ assertNull(encoder->error, "Encoder does not have a null error");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+LONGBOW_TEST_CASE(Encoder, ccnxCodecTlvEncoder_ClearError_Missing)
+{
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+
+ ccnxCodecTlvEncoder_ClearError(encoder);
+ assertNull(encoder->error, "Encoder does not have a null error");
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+}
+
+// ============================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _ccnxCodecTlvEncoder_ComputeVarIntLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _ccnxCodecTlvEncoder_ComputeVarIntLength)
+{
+ struct test_vector {
+ uint64_t value;
+ int length;
+ } vectors[] = {
+ { .value = 0, .length = 1 },
+ { .value = 0xFF, .length = 1 },
+ { .value = 0x0101, .length = 2 },
+ { .value = 0xFF01, .length = 2 },
+ { .value = 0x010001, .length = 3 },
+ { .value = 0xFF0001, .length = 3 },
+ { .value = 0x01000000, .length = 4 },
+ { .value = 0xFF002001, .length = 4 },
+ { .value = 0x0100000000, .length = 5 },
+ { .value = 0xFF00002001, .length = 5 },
+ { .value = 0x010000000000, .length = 6 },
+ { .value = 0xFF0000002001, .length = 6 },
+ { .value = 0x01000000000000, .length = 7 },
+ { .value = 0xFF000000002001, .length = 7 },
+ { .value = 0xFF00200103040506ULL, .length = 8 },
+ // sentinal is length 0
+ { .value = 0, .length = 0 },
+ };
+
+ for (int i = 0; vectors[i].length != 0; i++) {
+ unsigned test = _ccnxCodecTlvEncoder_ComputeVarIntLength(vectors[i].value);
+ assertTrue(test == vectors[i].length, "Incorrect length index %d, expected %u got %u", i, vectors[i].length, test);
+ }
+}
+
+
+// ===================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Tlv);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c
new file mode 100644
index 00000000..2dfdfcb3
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Does not do detailed tests of the decode -- those are tested in the individual schema_vX unit tests.
+ * These tests make sure that we (a) get a result when we expect to get a results, and (b) will spot-check
+ * the result, such as looking at the Name.
+ *
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+#include <config.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#include "../ccnxCodec_TlvPacket.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+#include <ccnx/common/validation/ccnxValidation_HmacSha256.h>
+
+#include <ccnx/common/ccnx_Interest.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+
+#include <ccnx/common/internal/ccnx_InterestDefault.h>
+
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h>
+
+LONGBOW_TEST_RUNNER(rta_TlvPacket)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(rta_TlvPacket)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_TlvPacket)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_BufferDecode_V1);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_BufferDecode_VFF);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_OneBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_SeveralBuffer);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_V1);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_VFF);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_V1);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_VFF);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_EncodeWithSignature);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_GetPacketLength);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_MinimalHeaderLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, rtaTlvPacket_BufferDecode_V1)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ PARCBuffer *interestMessage = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+ parcBufferComposer_PutBuffer(composer, interestMessage);
+ parcBuffer_Release(&interestMessage);
+
+ // Append extraneous data to the end of the buffer to make sure the decoder terminates at the end of the CCNx message.
+ PARCBuffer *padding = parcBuffer_AllocateCString("ThisShouldNeverBeParsed");
+ parcBufferComposer_PutBuffer(composer, padding);
+ parcBuffer_Release(&padding);
+ PARCBuffer *packetBuffer = parcBufferComposer_CreateBuffer(composer);
+ parcBufferComposer_Release(&composer);
+ parcBuffer_Rewind(packetBuffer);
+
+ //PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecTlvPacket_BufferDecode(packetBuffer, dict);
+ assertTrue(success, "Failed to decode good v1 interest");
+
+ CCNxName *name = ccnxInterest_GetName(dict);
+ assertNotNull(name, "Did not find a name in the decoded interest");
+
+ ccnxTlvDictionary_Release(&dict);
+ parcBuffer_Release(&packetBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, rtaTlvPacket_BufferDecode_VFF)
+{
+ uint8_t encoded[] = {
+ 0xFF, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ bool success = ccnxCodecTlvPacket_BufferDecode(packetBuffer, dict);
+ assertFalse(success, "Did not fail on decode of version 255 packet");
+
+ ccnxTlvDictionary_Release(&dict);
+ parcBuffer_Release(&packetBuffer);
+}
+
+typedef struct allocator_arg {
+ size_t maxallocation;
+} AllocatorArg;
+
+static size_t
+testAllocator(void *userarg, size_t bytes, void **output)
+{
+ AllocatorArg *arg = userarg;
+ if (bytes > arg->maxallocation) {
+ bytes = arg->maxallocation;
+ }
+
+ *output = parcMemory_Allocate(bytes);
+ assertNotNull(*output, "parcMemory_Allocate(%zu) returned NULL", bytes);
+ if (*output) {
+ return bytes;
+ }
+ return 0;
+}
+
+static void
+testDeallocator(void *userarg, void **memory)
+{
+ parcMemory_Deallocate((void **) memory);
+}
+
+const CCNxCodecNetworkBufferMemoryBlockFunctions TestMemoryBlock = {
+ .allocator = &testAllocator,
+ .deallocator = &testDeallocator
+};
+
+
+static void
+runIoVecTest(AllocatorArg maxalloc)
+{
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&TestMemoryBlock, &maxalloc);
+
+ ccnxCodecNetworkBuffer_PutArray(netbuff,
+ sizeof(v1_interest_all_fields),
+ v1_interest_all_fields);
+
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+
+ CCNxTlvDictionary *output = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+
+ ccnxTlvDictionary_SetMessageType_Interest(output, CCNxTlvDictionary_SchemaVersion_V1);
+
+ bool success = ccnxCodecTlvPacket_IoVecDecode(vec, output);
+ assertTrue(success, "Failed to decode buffer in iovec format");
+
+ ccnxTlvDictionary_Release(&output);
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+}
+
+LONGBOW_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_OneBuffer)
+{
+ AllocatorArg maxalloc = { .maxallocation = 2048 };
+ runIoVecTest(maxalloc);
+}
+
+LONGBOW_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_SeveralBuffer)
+{
+ // 32 bytes is needed for bookkeeping, so this means we'll have a 32-byte memory block
+ AllocatorArg maxalloc = { .maxallocation = 64 };
+ runIoVecTest(maxalloc);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_V1)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/Antidisestablishmentarianism");
+ CCNxTlvDictionary *message =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, CCNxInterestDefault_HopLimit);
+
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(message, NULL);
+ assertNotNull(iovec, "Got null iovec on a good dictionary");
+
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+ ccnxTlvDictionary_Release(&message);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_VFF)
+{
+ CCNxTlvDictionary *message = ccnxTlvDictionary_Create(20, 20);
+ ccnxTlvDictionary_SetMessageType_Interest(message, 0xFF);
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(message, NULL);
+ assertNull(iovec, "Should have gotten null result for schema version 255");
+ ccnxTlvDictionary_Release(&message);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_V1)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ PARCBuffer *interestMessage = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+ parcBufferComposer_PutBuffer(composer, interestMessage);
+ parcBuffer_Release(&interestMessage);
+
+ // Append extraneous data to the end of the buffer to make sure the decoder terminates at the end of the CCNx message.
+ PARCBuffer *padding = parcBuffer_AllocateCString("ThisShouldNeverBeParsed");
+ parcBufferComposer_PutBuffer(composer, padding);
+ parcBuffer_Release(&padding);
+ PARCBuffer *packetBuffer = parcBufferComposer_CreateBuffer(composer);
+ parcBufferComposer_Release(&composer);
+ parcBuffer_Rewind(packetBuffer);
+
+ CCNxTlvDictionary *dict = ccnxCodecTlvPacket_Decode(packetBuffer);
+ assertNotNull(dict, "Got null dictionary decoding good packet");
+
+ ccnxTlvDictionary_Release(&dict);
+ parcBuffer_Release(&packetBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_VFF)
+{
+ uint8_t encoded[] = {
+ 0xFF, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+
+ CCNxTlvDictionary *dict = ccnxCodecTlvPacket_Decode(packetBuffer);
+ assertNull(dict, "Got non-null dictionary decoding version 255 packet");
+ parcBuffer_Release(&packetBuffer);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_EncodeWithSignature)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar");
+ PARCBuffer *payload = parcBuffer_WrapCString("payload");
+ CCNxContentObject *obj = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ ccnxName_Release(&name);
+ parcBuffer_Release(&payload);
+
+ PARCBuffer *secretKey = parcBuffer_WrapCString("abcdefghijklmnopqrstuvwxyx");
+ PARCSigner *signer = ccnxValidationHmacSha256_CreateSigner(secretKey);
+
+ // should really scrub the memory
+ parcBuffer_Release(&secretKey);
+
+ // this was breaking the signature
+ PARCKeyStore *keyStore = parcSigner_GetKeyStore(signer);
+ const PARCCryptoHash *secretHash = parcKeyStore_GetVerifierKeyDigest(keyStore);
+ const PARCBuffer *keyid = parcCryptoHash_GetDigest(secretHash);
+ ccnxValidationHmacSha256_Set(obj, keyid);
+ parcCryptoHash_Release((PARCCryptoHash **) &secretHash);
+
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(obj, signer);
+
+ ccnxCodecNetworkBufferIoVec_Display(iovec, 0);
+
+ int fd = open("/dev/null", O_WRONLY);
+ assertTrue(fd != -1, "Error opening /dev/null");
+
+ ssize_t written = writev(fd, ccnxCodecNetworkBufferIoVec_GetArray(iovec), ccnxCodecNetworkBufferIoVec_GetCount(iovec));
+ assertTrue(written != -1, "Error writting to /dev/null");
+ close(fd);
+
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+ parcSigner_Release(&signer);
+ ccnxContentObject_Release(&obj);
+}
+
+static uint8_t testDataV1_Interest_AllFields[] = {
+ 0x01, 0x00, 0x00, 100, // ver = 1, type = interest, length = 100
+ 0x20, 0x00, 0x11, 14, // HopLimit = 32, reserved = 0, flags = 0x11, header length = 14
+ // ------------------------
+ 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes)
+ 0xEA, 0xEB,
+ // ------------------------
+ 0x00, 0x01, 0x00, 82, // type = interest, length = 82
+ // ------------------------
+ 0x00, 0x00, 0x00, 8, // type = name, length = 8
+ 0x00, 0x02, 0x00, 4, // type = binary, length = 4
+ 'c', 'o', 'o', 'l', // "cool"
+ // ------------------------
+ 0x00, 0x02, 0x00, 16, // type = keyid restriction, length = 16
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab,
+ 0xac, 0xad, 0xae, 0xaf,
+ // ------------------------
+ 0x00, 0x03, 0x00, 32, // type = hash restriction, length = 32
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb,
+ 0xcc, 0xcd, 0xce, 0xcf,
+ // ------------------------
+ 0x00, 0x04, 0x00, 1, // Internest payload method (1 byte)
+ 0x00,
+ // ------------------------
+ 0x00, 0x01, 0x00, 5, // type = payload, length = 5
+ 0xD0, 0xD1, 0xD2, 0xD3,
+ 0xD4,
+};
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_GetPacketLength)
+{
+ PARCBuffer *packet = parcBuffer_Wrap(testDataV1_Interest_AllFields, sizeof(testDataV1_Interest_AllFields), 0, sizeof(testDataV1_Interest_AllFields));
+ size_t packetLength = ccnxCodecTlvPacket_GetPacketLength(packet);
+ assertTrue(packetLength == sizeof(testDataV1_Interest_AllFields), "Wrong total message length, expected %zu got %zu", sizeof(testDataV1_Interest_AllFields), packetLength);
+ parcBuffer_Release(&packet);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_MinimalHeaderLength)
+{
+ assertTrue(ccnxCodecTlvPacket_MinimalHeaderLength() > 0, "ccnxCodecTlvPacket_MinimalHeaderLength failed");
+}
+
+// =================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Interest);
+ LONGBOW_RUN_TEST_CASE(Global, _decodeV1_ContentObject);
+ LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Control);
+ LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Unknown);
+ LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Error);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, _decodeV1_Interest)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields));
+ CCNxTlvDictionary *dict = _decodeV1(packetBuffer);
+ assertNotNull(dict, "Error decoding good packet");
+
+ CCNxName *name = ccnxInterest_GetName(dict);
+ assertNotNull(name, "Null name in decoded Interest");
+
+ ccnxTlvDictionary_Release(&dict);
+ parcBuffer_Release(&packetBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, _decodeV1_ContentObject)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256));
+ CCNxTlvDictionary *dict = _decodeV1(packetBuffer);
+ assertNotNull(dict, "Error decoding good packet");
+
+ CCNxName *name = ccnxContentObject_GetName(dict);
+ assertNotNull(name, "Null name in decoded Interest");
+
+ ccnxTlvDictionary_Release(&dict);
+ parcBuffer_Release(&packetBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, _decodeV1_Control)
+{
+ testUnimplemented("V1 control not implemented yet");
+}
+
+LONGBOW_TEST_CASE(Global, _decodeV1_Unknown)
+{
+ uint8_t encoded[] = {
+ 0x01, 0xFF, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxTlvDictionary *dict = _decodeV1(packetBuffer);
+ assertNull(dict, "Should have gotten NULL dictionary from unknown packet type");
+
+ parcBuffer_Release(&packetBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, _decodeV1_Error)
+{
+ PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_bad_message_length, sizeof(v1_interest_bad_message_length), 0, sizeof(v1_interest_bad_message_length));
+ CCNxTlvDictionary *dict = _decodeV1(packetBuffer);
+ assertNull(dict, "Should have gotten NULL dictionary from unknown packet type");
+
+ parcBuffer_Release(&packetBuffer);
+}
+
+// =================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_TlvPacket);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvUtilities.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvUtilities.c
new file mode 100644
index 00000000..b8215822
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvUtilities.c
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxCodec_TlvUtilities.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+#include <inttypes.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+
+typedef struct test_data {
+ uint8_t *packet;
+ PARCBuffer *fixedHeader;
+ CCNxCodecTlvDecoder *decoder;
+ CCNxTlvDictionary *dictionary;
+
+ // truth table
+ uint8_t version;
+ uint8_t packetType;
+ uint16_t packetLength;
+ uint8_t headerLength;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->packet = parcMemory_Allocate(8);
+ assertNotNull(data->packet, "parcMemory_Allocate(%u) returned NULL", 8);
+
+ // Make a V1 fixed header
+ memcpy(data->packet, &((uint8_t[]) {
+ 0x01, // version
+ 0x01, // packetType
+ 0x01, 0x02, // packetLength
+ 0x00, // hopLimit/hopCount
+ 0x00, // returnCode
+ 0x03, // flags
+ 0x04 // headerLength
+ }), 8);
+
+
+ data->fixedHeader = parcBuffer_Wrap(data->packet, 8, 0, 8);
+ data->version = 1;
+ data->packetType = 1;
+ data->packetLength = 0x0102;
+ data->headerLength = 0x04;
+ data->decoder = ccnxCodecTlvDecoder_Create(data->fixedHeader);
+ data->dictionary = ccnxTlvDictionary_Create(10, 10);
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ ccnxTlvDictionary_Release(&data->dictionary);
+ ccnxCodecTlvDecoder_Destroy(&data->decoder);
+ parcBuffer_Release(&data->fixedHeader);
+ parcMemory_Deallocate((void **) &(data->packet));
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(rta_TlvUtilities)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(rta_TlvUtilities)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_TlvUtilities)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_GetVarInt);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_DecodeContainer);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_DecodeSubcontainer);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsHash);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsListBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_NestedEncode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvUtilities_EncodeCustomList);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsBuffer)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint32_t type = 1;
+ uint32_t length = 8;
+
+ bool success = ccnxCodecTlvUtilities_PutAsBuffer(data->decoder, data->dictionary, type, length,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader);
+
+ assertTrue(success, "Failed to save buffer slice");
+
+ int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(data->dictionary);
+ assertTrue(version == data->version, "Wrong version, got %d expected %d", version, data->version);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsHash)
+{
+ uint8_t encoded[] = {
+ 0x00, 0x01, 0x00, 0x20, // 0x01 = CCNxCodecSchemaV1Types_HashType_SHA256
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer);
+
+ uint16_t type = 0x01;
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, 10);
+ bool success = ccnxCodecTlvUtilities_PutAsHash(decoder, dictionary, type, sizeof(encoded),
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION);
+ assertTrue(success, "Failed to save hash");
+
+ parcBuffer_Release(&tlvBuffer);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_GetVarInt)
+{
+ struct test_vector {
+ uint64_t value;
+ bool valid;
+ int length;
+ uint8_t *array;
+ } vectors[] = {
+ // length 0 invalid
+ { .value = 0, .valid = false, .length = 0, .array = (uint8_t[]) { 0x00 } },
+ { .value = 0, .valid = true, .length = 1, .array = (uint8_t[]) { 0x00 } },
+ { .value = 0xFF, .valid = true, .length = 1, .array = (uint8_t[]) { 0xFF } },
+ { .value = 0x0001, .valid = true, .length = 2, .array = (uint8_t[]) { 0x00, 0x01} },
+ { .value = 0xFF01, .valid = true, .length = 2, .array = (uint8_t[]) { 0xFF, 0x01} },
+ { .value = 0x000001, .valid = true, .length = 3, .array = (uint8_t[]) { 0x00, 0x00, 0x01} },
+ { .value = 0xFF0001, .valid = true, .length = 3, .array = (uint8_t[]) { 0xFF, 0x00, 0x01} },
+ { .value = 0x00000001, .valid = true, .length = 4, .array = (uint8_t[]) { 0x00, 0x00, 0x00, 0x01} },
+ { .value = 0xFF002001, .valid = true, .length = 4, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01} },
+ { .value = 0xFF00200103040506ULL, .valid = true, .length = 8, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06} },
+ // length 9 invalid
+ { .value = 0, .valid = false, .length = 9, .array = (uint8_t[]) { 0xFF, 0x00, 0x20, 0x01, 0x03, 0x04, 0x05, 0x06, 0x07} },
+ // sentinal is NULL array
+ { .value = 0, .valid = false, .length = 0, .array = NULL },
+ };
+
+ for (int i = 0; vectors[i].array != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_Wrap(vectors[i].array, vectors[i].length, 0, vectors[i].length);
+
+ uint64_t value;
+ bool success = ccnxCodecTlvUtilities_GetVarInt(buffer, vectors[i].length, &value);
+ parcBuffer_Release(&buffer);
+
+ assertTrue(success == vectors[i].valid, "index %d: Wrong return, got %d expected %d", i, success, vectors[i].valid);
+ if (vectors[i].valid) {
+ assertTrue(value == vectors[i].value, "index %d: wrong value: got %" PRIu64 " expected %" PRIu64, i, value, vectors[i].value);
+ }
+ }
+}
+
+
+static bool
+_decodeSubContainer(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary)
+{
+ return true;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_DecodeSubcontainer)
+{
+ uint8_t metadata[] = {
+ 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17
+ 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1
+ 0x04, // LINK
+ 0x00, 0x0D, 0x00, 8, // Creation Time
+ 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec
+ 0x4B, 0x19, 0x84, 0x00,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(metadata, sizeof(metadata), 0, sizeof(metadata));
+
+ // now decode that snippit
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(20, 20);
+
+ uint16_t key = ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ bool success = ccnxCodecTlvUtilities_DecodeSubcontainer(decoder, dictionary, key, length, _decodeSubContainer);
+
+ assertTrue(success, "Failed to decode metadata container");
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+}
+
+
+static bool
+testTypeDecoder(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length)
+{
+ switch (type) {
+ case 0x000C: // fallthrough
+ case 0x000D:
+ ccnxCodecTlvDecoder_Advance(decoder, length);
+ return true;
+ default:
+ return false;
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_DecodeContainer)
+{
+ uint8_t metadataContainer[] = {
+ 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1
+ 0x04, // LINK
+ 0x00, 0x0D, 0x00, 8, // Creation Time
+ 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec
+ 0x4B, 0x19, 0x84, 0x00,
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(metadataContainer, sizeof(metadataContainer), 0, sizeof(metadataContainer));
+
+ // now decode that snippit
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10, 10);
+
+ bool success = ccnxCodecTlvUtilities_DecodeContainer(decoder, dictionary, testTypeDecoder);
+
+ ccnxTlvDictionary_Release(&dictionary);
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+
+ assertTrue(success, "The TLV types were known to us");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsName)
+{
+ // A list of 2 TLV containers (types 0x000C and 0x000D)
+ uint8_t nameContainer[] = {
+ 0x00, 0x00, 0x00, 9, // type = name, length = 9
+ 0x00, 0x03, 0x00, 5, // type = binary, length = 5
+ 'h', 'e', 'l', 'l', // "hello"
+ 'o',
+ };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(nameContainer, sizeof(nameContainer), 0, sizeof(nameContainer));
+
+ // now decode that snippit
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10, 10);
+
+ uint16_t tlvtype = ccnxCodecTlvDecoder_GetType(decoder);
+ uint16_t tlvlength = ccnxCodecTlvDecoder_GetLength(decoder);
+
+ // Saves "lci:/3=hello"
+ bool success = ccnxCodecTlvUtilities_PutAsName(decoder, dictionary, tlvtype, tlvlength, 1);
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&buffer);
+
+ assertTrue(success, "The Name failed to decode or some other error");
+
+ CCNxName *truth = ccnxName_CreateFromCString("lci:/3=hello");
+ CCNxName *test = ccnxTlvDictionary_GetName(dictionary, 1);
+ assertTrue(ccnxName_Equals(truth, test), "Names not equal")
+ {
+ ccnxName_Display(test, 3);
+ ccnxName_Display(truth, 3);
+ ccnxName_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+ }
+
+ ccnxName_Release(&truth);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_PutAsListBuffer)
+{
+ uint8_t array[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ PARCBuffer *buffer = parcBuffer_Wrap(array, sizeof(array), 0, sizeof(array));
+
+ PARCBuffer *truth[3];
+ truth[0] = parcBuffer_Wrap(array, sizeof(array), 0, 2);
+ truth[1] = parcBuffer_Wrap(array, sizeof(array), 2, 3);
+ truth[2] = parcBuffer_Wrap(array, sizeof(array), 3, 6);
+
+ CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer);
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10, 10);
+
+ // put 3 buffers of {0x01, 0x02} and {0x03} and {0x04, 0x05, x06} on the list
+ int listkey = 1;
+ ccnxCodecTlvUtilities_PutAsListBuffer(decoder, dictionary, 0, 2, listkey);
+ ccnxCodecTlvUtilities_PutAsListBuffer(decoder, dictionary, 1, 1, listkey);
+ ccnxCodecTlvUtilities_PutAsListBuffer(decoder, dictionary, 2, 3, listkey);
+
+ assertTrue(ccnxTlvDictionary_ListSize(dictionary, listkey) == 3,
+ "Wrong list size, got %zu expected %u",
+ ccnxTlvDictionary_ListSize(dictionary, listkey), 3);
+
+ // now make sure they are right
+ for (int i = 0; i < ccnxTlvDictionary_ListSize(dictionary, listkey); i++) {
+ PARCBuffer *test = ccnxTlvDictionary_ListGetByType(dictionary, listkey, i);
+ assertNotNull(test, "Failed to get index %d", i);
+
+ assertTrue(parcBuffer_Equals(truth[i], test), "Buffers not equal for index %d", i)
+ {
+ parcBuffer_Display(test, 3);
+ parcBuffer_Display(truth[i], 3);
+ }
+ }
+
+ ccnxCodecTlvDecoder_Destroy(&decoder);
+ parcBuffer_Release(&truth[0]);
+ parcBuffer_Release(&truth[1]);
+ parcBuffer_Release(&truth[2]);
+ parcBuffer_Release(&buffer);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_NestedEncode)
+{
+// TODO: This test needs to be updated with V1 data.
+// See BugzID: 3919
+
+
+// uint8_t metadata[] = {
+// 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17
+// 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1
+// 0x04, // LINK
+// 0x00, 0x0D, 0x00, 8, // Creation Time
+// 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec
+// 0x4B, 0x19, 0x84, 0x00,
+// };
+//
+//
+// PARCBuffer *truth = parcBuffer_Wrap(metadata, sizeof(metadata), 0, sizeof(metadata));
+//
+// // now decode that snippit
+// CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(truth);
+// CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(20, 20);
+// ccnxCodecTlvDecoder_Advance(decoder, 4);
+// ccnxCodecTlvUtilities_DecodeContainer(decoder, dictionary, _ccnxCodecSchemaV0MetadataDecoder_DecodeType);
+//
+// // the dictionary should now be ready for encoding
+// ccnxCodecTlvDecoder_Destroy(&decoder);
+//
+// CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+// ssize_t length = ccnxCodecTlvUtilities_NestedEncode(encoder, dictionary, 0x000B, ccnxCodecSchemaV0MetadataEncoder_Encode);
+//
+// assertTrue(length == sizeof(metadata), "Wrong size, got %zu expected %zu", length, sizeof(metadata));
+//
+// ccnxCodecTlvEncoder_Finalize(encoder);
+// PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+// assertTrue(parcBuffer_Equals(test, truth), "Buffers do not match")
+// {
+// parcBuffer_Display(test, 3);
+// parcBuffer_Display(truth, 3);
+// }
+//
+// ccnxCodecTlvEncoder_Destroy(&encoder);
+// ccnxTlvDictionary_Release(&dictionary);
+// parcBuffer_Release(&truth);
+// parcBuffer_Release(&test);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxCodecTlvUtilities_EncodeCustomList)
+{
+ uint8_t truthArray[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 0x02,
+ 0x00, 0x01, 0x00, 0x01, 0x03,
+ 0x00, 0x02, 0x00, 0x03, 0x04, 0x05, 0x06 };
+
+ PARCBuffer *truth = parcBuffer_Wrap(truthArray, sizeof(truthArray), 0, sizeof(truthArray));
+
+ PARCBuffer *buffers[3];
+ buffers[0] = parcBuffer_Wrap(truthArray, sizeof(truthArray), 4, 6);
+ buffers[1] = parcBuffer_Wrap(truthArray, sizeof(truthArray), 10, 11);
+ buffers[2] = parcBuffer_Wrap(truthArray, sizeof(truthArray), 15, 18);
+
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10, 10);
+
+ // put 3 buffers of {0x01, 0x02} and {0x03} and {0x04, 0x05, x06} on the list
+ int listkey = 1;
+ ccnxTlvDictionary_PutListBuffer(dictionary, listkey, 2, buffers[2]);
+ ccnxTlvDictionary_PutListBuffer(dictionary, listkey, 1, buffers[1]);
+ ccnxTlvDictionary_PutListBuffer(dictionary, listkey, 0, buffers[0]);
+
+ CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create();
+ ccnxCodecTlvUtilities_EncodeCustomList(encoder, dictionary, listkey);
+
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ assertTrue(parcBuffer_Equals(test, truth), "Buffers not equal")
+ {
+ parcBuffer_Display(test, 3);
+ parcBuffer_Display(truth, 3);
+ }
+
+ ccnxCodecTlvEncoder_Destroy(&encoder);
+ parcBuffer_Release(&buffers[0]);
+ parcBuffer_Release(&buffers[1]);
+ parcBuffer_Release(&buffers[2]);
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&test);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+// ====================================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_TlvUtilities);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/codec/test/test_random_bytes b/libccnx-common/ccnx/common/codec/test/test_random_bytes
new file mode 100644
index 00000000..33a80af5
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_random_bytes
Binary files differ
diff --git a/libccnx-common/ccnx/common/codec/test/test_random_bytes.sig b/libccnx-common/ccnx/common/codec/test/test_random_bytes.sig
new file mode 100644
index 00000000..9c395ce0
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_random_bytes.sig
Binary files differ
diff --git a/libccnx-common/ccnx/common/codec/test/test_rsa.p12 b/libccnx-common/ccnx/common/codec/test/test_rsa.p12
new file mode 100644
index 00000000..471c4006
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_rsa.p12
Binary files differ
diff --git a/libccnx-common/ccnx/common/codec/test/test_rsa_key.pem b/libccnx-common/ccnx/common/codec/test/test_rsa_key.pem
new file mode 100644
index 00000000..6c502b15
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/test_rsa_key.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCn1pPF8XPGErX6ecXvGIvvqs0EAY+Ddz+xZqFauTkqsj4w+xH8
+V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEOJEKN5nWgTgRDDD5MBnRnrYTD
+6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8qPD0PNZKucCf70uQeJwIDAQAB
+AoGAVOYPA/7aIGSQlu4IOKTDDG3qnM8pSEgG+PbAQgMVrspQ+TfXZj0ftLj++P3N
+zpDw8P6BVUfBQs2FNG/ZwEhaiZVgJAl7cIAxJ9Ac+1oZYSgGyJfb3u9iWvkbMOoj
+83Inx5yyN+Qmk5zceH4pOC5D5cDAuGGZ740Euv4o2/2O3qECQQDTmWZw021PvEbA
+r18O1YfZGxO3zFCwFXCpnHvtSMbP+MXAG5Gt47wZt4Vx1rX9k78beeCUitwqp3d3
+ZI+YlUu3AkEAyw5wssQsJty/n2FL8DbJN3UzUhkcaCFYrKz3RtFye9wu+Bw0TxPC
+3jhFVcynm3nH3ZJN0JsnsPnHXuoQToShEQJATXC51hb6zZC5UDGel348fo9zUvP6
+n8bo+ZoknL3izSBdtyYf1cUgBUVuGDCdYFWfPn4HXDXJx+6MQWzTRON21wJBAMZL
+U8M/z94jtP3wBjiPR/Dggz2pSBRofDAkuVZvM13BqByjbnHK2oIocY1YTlWGl6fJ
+ODR/UEODqS8HZOVIoAECQANcuvVnqDixSIl2ySZvydQytv4DKTbvE0nYSRroYIlJ
+PTOBPy8ynIUkJwc2E1BsLl7V8gO62a5O0ntTwBMnPSQ=
+-----END RSA PRIVATE KEY-----
diff --git a/libccnx-common/ccnx/common/codec/test/testrig_Compare.c b/libccnx-common/ccnx/common/codec/test/testrig_Compare.c
new file mode 100755
index 00000000..3dc73a1c
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/test/testrig_Compare.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Utilities used by the Schema unit tests to compare buffers
+ *
+ */
+
+/**
+ * Compares an encoding buffer to linear memory
+ *
+ * Will assert if the memory does not compare. The encoding buffer will be finalized.
+ * Will assert if the encoder has an error.
+ *
+ * @param [in] encoder The encoding buffer to compare
+ * @param [in] length The length of linear memory
+ * @param [in] memory The "truth" memory to compare against
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+testCompareEncoderToLinearMemory(CCNxCodecTlvEncoder *encoder, size_t length, uint8_t memory[length])
+{
+ assertFalse(ccnxCodecTlvEncoder_HasError(encoder), "Encoder has error")
+ {
+ printf("ERROR: %s\n", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ }
+
+ PARCBuffer *truth = parcBuffer_Wrap(memory, length, 0, length);
+ ccnxCodecTlvEncoder_Finalize(encoder);
+ PARCBuffer *buffer = ccnxCodecTlvEncoder_CreateBuffer(encoder);
+
+ assertTrue(parcBuffer_Equals(buffer, truth), "buffers not equal")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(truth, 3);
+
+ printf("Got this\n");
+ parcBuffer_Display(buffer, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ parcBuffer_Release(&buffer);
+}
+
+/**
+ * Compares an encoding buffer to a PARCBuffer
+ *
+ * Will assert if the memory does not compare. The encoding buffer will be finalized.
+ * Will assert if the encoder has an error.
+ *
+ * @param [in] encoder The encoding buffer to compare
+ * @param [in] buffer The buffer to compare to, must be setup to be read (i.e. flipped)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+testCompareEncoderToBuffer(CCNxCodecTlvEncoder *encoder, PARCBuffer *buffer)
+{
+ assertFalse(ccnxCodecTlvEncoder_HasError(encoder), "Encoder has error")
+ {
+ printf("ERROR: %s\n", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder)));
+ }
+
+
+ uint8_t *linearMemory = parcByteArray_Array(parcBuffer_Array(buffer));
+ size_t offset = parcBuffer_ArrayOffset(buffer) + parcBuffer_Position(buffer);
+ size_t length = parcBuffer_Remaining(buffer);
+
+ testCompareEncoderToLinearMemory(encoder, length, linearMemory + offset);
+}
+
diff --git a/libccnx-common/ccnx/common/codec/testdata/testdata_common.h b/libccnx-common/ccnx/common/codec/testdata/testdata_common.h
new file mode 100644
index 00000000..ac1d0b8e
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/testdata/testdata_common.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ * testdata_common.h
+ * TransportRTA
+ */
+
+#ifndef TransportRTA_testdata_common_h
+#define TransportRTA_testdata_common_h
+
+#include <ccnx/common/codec/ccnxCodec_Error.h>
+
+typedef struct tlv_extent {
+ uint16_t offset;
+ uint16_t length;
+} TlvExtent;
+
+// Equal to { 0xFFFF, 0xFFFF }
+extern const TlvExtent TlvExtentNotFound;
+
+/**
+ * Determine if two TlvExtent instances are equal.
+ *
+ * The following equivalence relations on non-null `TlvExtent` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `TlvExtent_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `tlvExtent_Equals(x, y)` must return true if and only if
+ * `tlvExtent_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `tlvExtent_Equals(x, y)` returns true and
+ * `tlvExtent_Equals(y, z)` returns true,
+ * then `tlvExtent_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `tlvExtent_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `tlvExtent_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `TlvExtent` instance.
+ * @param b A pointer to a `TlvExtent` instance.
+ * @return true if the two `TlvExtent` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * TlvExtent *a = tlvExtent_Create();
+ * TlvExtent *b = tlvExtent_Create();
+ *
+ * if (tlvExtent_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool tlvExtent_Equals(const TlvExtent *a, const TlvExtent *b);
+
+#define TRUTHTABLENAME(NAME) NAME ## _truthTableEntries
+
+// easy way to generate table entries, so long as you use the standard naming
+// convention for the the TruthTableEntry array
+#define TABLEENTRY(NAME, ERROR) { .testname = #NAME, .packet = NAME, .length = sizeof(NAME), .expectedError = ERROR, .entry = TRUTHTABLENAME(NAME) }
+
+typedef struct testrig_truth_table_entry {
+ bool wellKnownType;
+
+ // is the wellKnownType in the body manifest? or the header?
+ bool bodyManifest;
+
+ // if its a well known type, this is the manifest array index
+ // otherwise, its the unknown type value
+ int indexOrKey;
+
+ TlvExtent extent;
+} TruthTableEntry;
+
+
+typedef struct testrig_truth_table {
+ const char *testname;
+ uint8_t *packet;
+ size_t length;
+
+ CCNxCodecErrorCodes expectedError;
+
+ // the array is terminated by a T_INVALID value
+ // for "arrayIndexOrTypeKey"
+ TruthTableEntry *entry;
+} TruthTable;
+
+#endif
diff --git a/libccnx-common/ccnx/common/codec/testdata/tlv_Schema.h b/libccnx-common/ccnx/common/codec/testdata/tlv_Schema.h
new file mode 100755
index 00000000..ddd8df7d
--- /dev/null
+++ b/libccnx-common/ccnx/common/codec/testdata/tlv_Schema.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This is from the version 0 codec. All the test vectors in this directory (e.g. interest_nameA.h)
+ * are encoded using these constants. These are no longer used for any functional code, only to interpret the test vectors.
+ *
+ */
+
+#ifndef Libccnx_tlv_Schema_h
+#define Libccnx_tlv_Schema_h
+
+#define T_INVALID 0xFFFF
+
+// not an actual type, but a virtual group
+#define T_VIRTUAL 0xFFFE
+#endif // Libccnx_tlv_Schema_h
diff --git a/libccnx-common/ccnx/common/config.h.in b/libccnx-common/ccnx/common/config.h.in
new file mode 100644
index 00000000..5d047cfc
--- /dev/null
+++ b/libccnx-common/ccnx/common/config.h.in
@@ -0,0 +1,4 @@
+/* CPU Cache line size */
+#define LEVEL1_DCACHE_LINESIZE @LEVEL1_DCACHE_LINESIZE@
+
+#define _GNU_SOURCE
diff --git a/libccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.c
new file mode 100755
index 00000000..5af1b5ca
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/internal/ccnx_ChunkingFacadeV1.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+static void
+_assertInvariants(const CCNxTlvDictionary *dictionary)
+{
+ assertNotNull(dictionary, "Parameter contentObjectDictionary must be non-null");
+ trapIllegalValueIf(ccnxTlvDictionary_GetSchemaVersion(dictionary) != CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema version, expected %d got %d",
+ CCNxTlvDictionary_SchemaVersion_V1,
+ ccnxTlvDictionary_GetSchemaVersion(dictionary));
+}
+
+bool
+ccnxChunkingFacadeV1_HasEndChunkNumber(const CCNxTlvDictionary *contentObjectDictionary)
+{
+ _assertInvariants(contentObjectDictionary);
+ return ccnxTlvDictionary_IsValueInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT);
+}
+
+uint64_t
+ccnxChunkingFacadeV1_GetEndChunkNumber(const CCNxTlvDictionary *contentObjectDictionary)
+{
+ _assertInvariants(contentObjectDictionary);
+ return ccnxTlvDictionary_GetInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT);
+}
+
+bool
+ccnxChunkingFacadeV1_SetEndChunkNumber(CCNxTlvDictionary *contentObjectDictionary, uint64_t endChunkNumber)
+{
+ _assertInvariants(contentObjectDictionary);
+ trapIllegalValueIf(!ccnxTlvDictionary_IsContentObject(contentObjectDictionary), "Dictionary is not a ContentObject");
+ return ccnxTlvDictionary_PutInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT, endChunkNumber);
+}
diff --git a/libccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.h
new file mode 100755
index 00000000..a4d2010c
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_ChunkingFacadeV1.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_ChunkingFacade.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef libccnx_ccnx_ChunkingFacadeV1_h
+#define libccnx_ccnx_ChunkingFacadeV1_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+/**
+ * Determines if an EndChunkNumber exists in the metadata
+ *
+ * Compatible with V0 and V1 schemas.
+ *
+ * @param [in] contentObjectDictionary A dictionary to check
+ *
+ * @return false There is no EndChunkNumber specified or the dictinoary is not a ContentObject
+ * @return true There is an EndChunkNumber specified
+ *
+ * Example:
+ * @code
+ * static PARCElasticBuffer *
+ * _ccnxContentObjectFacade_CreateFinalBlockId(const CCNxTlvDictionary *contentObjectDictionary)
+ * {
+ * if (ccnxChunkingFacade_HasEndChunkNumber(contentObjectDictionary)) {
+ * uint64_t endChunkNumber = ccnxChunkingFacade_GetEndChunkNumber(contentObjectDictionary);
+ * PARCElasticBuffer *fbid = _ccnxContentObjectFacade_EncodeFinalBlockId(endChunkNumber);
+ * return fbid;
+ * }
+ * return NULL;
+ * }
+ * @endcode
+ */
+bool ccnxChunkingFacadeV1_HasEndChunkNumber(const CCNxTlvDictionary *contentObjectDictionary);
+
+/**
+ * Retrieves the end chunk number
+ *
+ * Retieves the end chunk number as an unsigned 64-bit integer.
+ * This function will trapIllegalValue if there is not an EndChunkNumber present.
+ * The EndChunkNumber is the chunk number of the last Content Object in a chunked series.
+ *
+ * @param [in] contentObjectDictionary A dictionary to check
+ *
+ * @return number The ending chunk number
+ *
+ * Example:
+ * @code
+ * static PARCElasticBuffer *
+ * _ccnxContentObjectFacade_CreateFinalBlockId(const CCNxTlvDictionary *contentObjectDictionary)
+ * {
+ * if (ccnxChunkingFacade_HasEndChunkNumber(contentObjectDictionary)) {
+ * uint64_t endChunkNumber = ccnxChunkingFacade_GetEndChunkNumber(contentObjectDictionary);
+ * PARCElasticBuffer *fbid = _ccnxContentObjectFacade_EncodeFinalBlockId(endChunkNumber);
+ * return fbid;
+ * }
+ * return NULL;
+ * }
+ * @endcode
+ */
+uint64_t ccnxChunkingFacadeV1_GetEndChunkNumber(const CCNxTlvDictionary *contentObjectDictionary);
+
+/**
+ * Sets the EndChunkNumber of a ContentObject
+ *
+ * The dictionary must be a ContentObject, otherwise this function will trapIllegalValue.
+ * If an EndChunkNumber already exits, will not update but return false.
+ *
+ * @param [in] contentObjectDictionary A dictionary to check
+ * @param [in] endChunkNumber The ending chunk number
+ *
+ * @return true The value was set in the dictionary
+ * @return false A failure (likely value already set)
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTlvDictionary *obj = ccnxContentObjectFacade_Create(...);
+ * ccnxChunkingFacade_SetEndChunkNumber(obj, 74);
+ * }
+ * @endcode
+ */
+bool ccnxChunkingFacadeV1_SetEndChunkNumber(CCNxTlvDictionary *contentObjectDictionary, uint64_t endChunkNumber);
+#endif // libccnx_ccnx_ChunkingFacadeV1_h
diff --git a/libccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.c
new file mode 100644
index 00000000..1ca0c5af
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_SigningAlgorithm.h>
+
+#include <ccnx/common/internal/ccnx_ContentObjectFacadeV1.h>
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+#include <ccnx/common/internal/ccnx_ChunkingFacadeV1.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+
+static void
+_assertInvariants(const CCNxTlvDictionary *contentObjectDictionary)
+{
+ assertNotNull(contentObjectDictionary, "Dictionary is null");
+ assertTrue(ccnxTlvDictionary_IsContentObject(contentObjectDictionary), "Dictionary is not a content object");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(contentObjectDictionary) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Dictionary is wrong schema version, got %d expected %d",
+ ccnxTlvDictionary_GetSchemaVersion(contentObjectDictionary), CCNxTlvDictionary_SchemaVersion_V1);
+}
+
+// =========================
+// Creation
+
+static CCNxTlvDictionary *
+_ccnxContentObjectFacadeV1_CreateWithNameAndPayload(const CCNxName *name, // required
+ const CCNxPayloadType payloadType, // required
+ const PARCBuffer *payload) // may be null
+{
+ assertNotNull(name, "Parameter name must be non-null");
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+
+ if (dictionary) {
+ ccnxTlvDictionary_PutName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name);
+
+ if (payloadType != CCNxPayloadType_DATA) {
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE, payloadType);
+ }
+
+ if (payload) {
+ ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, payload);
+ }
+ } else {
+ trapOutOfMemory("Could not allocate ContentObject");
+ }
+
+ return dictionary;
+}
+
+static CCNxTlvDictionary *
+_ccnxContentObjectFacadeV1_CreateWithPayload(const CCNxPayloadType payloadType, // required
+ const PARCBuffer *payload) // may be null
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+
+ if (dictionary) {
+ if (payloadType != CCNxPayloadType_DATA) {
+ ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE, payloadType);
+ }
+
+ if (payload) {
+ ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, payload);
+ }
+ } else {
+ trapOutOfMemory("Could not allocate ContentObject");
+ }
+
+ return dictionary;
+}
+
+// =========================
+// Getters
+
+static CCNxName *
+_ccnxContentObjectFacadeV1_GetName(const CCNxTlvDictionary *contentObjectDictionary)
+{
+ _assertInvariants(contentObjectDictionary);
+ return ccnxTlvDictionary_GetName(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+}
+
+static bool
+_ccnxContentObjectFacadeV1_HasExpiryTime(const CCNxTlvDictionary *packetDictionary)
+{
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME)) {
+ return true;
+ }
+ return false;
+}
+
+static uint64_t
+_ccnxContentObjectFacadeV1_GetExpiryTime(const CCNxTlvDictionary *packetDictionary)
+{
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME)) {
+ return ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME);
+ }
+ trapUnexpectedState("The dictionary does not contain an Expiry Time");
+}
+
+static bool
+_ccnxContentObjectFacadeV1_HasPathLabel(const CCNxTlvDictionary *packetDictionary)
+{
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel)) {
+ return true;
+ }
+ return false;
+}
+
+
+static uint64_t
+_ccnxContentObjectFacadeV1_GetPathLabel(const CCNxTlvDictionary *packetDictionary)
+{
+ if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel)) {
+ return ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel);
+ }
+ trapUnexpectedState("The dictionary does not contain a Path Label");
+}
+
+static PARCBuffer *
+_ccnxContentObjectFacadeV1_GetPayload(const CCNxTlvDictionary *contentObjectDictionary)
+{
+ _assertInvariants(contentObjectDictionary);
+ return ccnxTlvDictionary_GetBuffer(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+}
+
+static CCNxPayloadType
+_ccnxContentObjectFacadeV1_GetPayloadType(const CCNxTlvDictionary *contentObjectDictionary)
+{
+ CCNxPayloadType result = CCNxPayloadType_DATA;
+
+ _assertInvariants(contentObjectDictionary);
+ if (ccnxTlvDictionary_IsValueInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE)) {
+ result = (CCNxPayloadType) ccnxTlvDictionary_GetInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE);
+ }
+
+ return result;
+}
+
+// =========================
+// Setters
+
+static bool
+_ccnxContentObjectFacadeV1_SetSignature(CCNxTlvDictionary *contentObject, const PARCBuffer *keyId,
+ const PARCSignature *signature, const CCNxKeyLocator *keyLocator)
+{
+ bool result = false;
+
+ CCNxTlvDictionary *contentObjectDictionary = (CCNxTlvDictionary *) contentObject;
+
+ if (parcSignature_GetSigningAlgorithm(signature) == PARCSigningAlgorithm_RSA
+ && parcSignature_GetHashType(signature) == PARCCryptoHashType_SHA256) {
+ ccnxValidationRsaSha256_Set(contentObjectDictionary, keyId, keyLocator);
+ } else if (parcSignature_GetSigningAlgorithm(signature) == PARCSigningAlgorithm_HMAC
+ && parcSignature_GetHashType(signature) == PARCCryptoHashType_SHA256) {
+ ccnxValidationHmacSha256_Set(contentObjectDictionary, keyId);
+ } else {
+ trapNotImplemented("Have not implemented the signature parameters");
+ }
+
+ PARCBuffer *sigbits = parcSignature_GetSignature(signature);
+
+ result = ccnxValidationFacadeV1_SetPayload(contentObjectDictionary, sigbits);
+
+ return result;
+}
+
+static PARCBuffer *
+_ccnxContentObjectFacadeV1_GetKeyId(const CCNxTlvDictionary *contentObject)
+{
+ return ccnxValidationFacadeV1_GetKeyId(contentObject);
+}
+
+static bool
+_ccnxContentObjectFacadeV1_SetExpiryTime(CCNxTlvDictionary *contentObjectDictionary, uint64_t expiryTime)
+{
+ bool success = ccnxTlvDictionary_PutInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME, expiryTime);
+ trapUnexpectedStateIf(!success, "Could not set integer in dictionary");
+ return success;
+}
+
+static bool
+_ccnxContentObjectFacadeV1_SetPathLabel(CCNxTlvDictionary *contentObjectDictionary, uint64_t pathLabel)
+{
+ bool success = ccnxTlvDictionary_PutInteger(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel, pathLabel);
+ trapUnexpectedStateIf(!success, "Could not set integer in dictionary (path label)");
+ return success;
+}
+
+static bool
+_ccnxContentObjectFacadeV1_SetPayload(CCNxTlvDictionary *contentObjectDictionary, CCNxPayloadType payloadType, const PARCBuffer *payload)
+{
+ bool result = false;
+
+ if (payload != NULL) {
+ PARCBuffer *originalPayload = _ccnxContentObjectFacadeV1_GetPayload(contentObjectDictionary);
+
+ result = ccnxTlvDictionary_PutBuffer(contentObjectDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, payload);
+
+ if (result) {
+ if (_ccnxContentObjectFacadeV1_GetPayloadType(contentObjectDictionary) != payloadType) {
+ ccnxTlvDictionary_PutInteger(contentObjectDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE, payloadType);
+ }
+
+ if (originalPayload != NULL) {
+ parcBuffer_Release(&originalPayload);
+ }
+ }
+ }
+
+ return result;
+}
+
+// =========================
+// Miscellaneous functions
+
+static bool
+_ccnxContentObjectFacadeV1_Equals(const CCNxTlvDictionary *objectA, const CCNxTlvDictionary *objectB)
+{
+ return ccnxTlvDictionary_Equals(objectA, objectB);
+}
+
+static char *
+_ccnxContentObjectFacadeV1_ToString(const CCNxTlvDictionary *contentObjectDictionary)
+{
+ trapNotImplemented("_ccnxContentObjectFacadeV1_ToString(): not yet implemented");
+}
+
+static void
+_ccnxContentObjectFacadeV1_Display(const CCNxTlvDictionary *contentObjectDictionary, size_t indentation)
+{
+ _assertInvariants(contentObjectDictionary);
+ ccnxTlvDictionary_Display(contentObjectDictionary, (unsigned) indentation);
+}
+
+/**
+ * `CCNxContentObjectFacadeV1_Implementation` is the structure containing the pointers to the
+ * V1 schema ContentObject implementation.
+ */
+CCNxContentObjectInterface CCNxContentObjectFacadeV1_Implementation = {
+ .description = "CCNxContentObjectFacadeV1_Implementation",
+
+ .createWithNameAndPayload = &_ccnxContentObjectFacadeV1_CreateWithNameAndPayload,
+ .createWithPayload = &_ccnxContentObjectFacadeV1_CreateWithPayload,
+
+ .setSignature = &_ccnxContentObjectFacadeV1_SetSignature,
+ .getKeyId = &_ccnxContentObjectFacadeV1_GetKeyId,
+
+ .getName = &_ccnxContentObjectFacadeV1_GetName,
+ .getPayload = &_ccnxContentObjectFacadeV1_GetPayload,
+ .setPayload = &_ccnxContentObjectFacadeV1_SetPayload,
+ .getPayloadType = &_ccnxContentObjectFacadeV1_GetPayloadType,
+
+ .getFinalChunkNumber = &ccnxChunkingFacadeV1_GetEndChunkNumber,
+ .setFinalChunkNumber = &ccnxChunkingFacadeV1_SetEndChunkNumber,
+ .hasFinalChunkNumber = &ccnxChunkingFacadeV1_HasEndChunkNumber,
+
+ .getExpiryTime = &_ccnxContentObjectFacadeV1_GetExpiryTime,
+ .setExpiryTime = &_ccnxContentObjectFacadeV1_SetExpiryTime,
+ .hasExpiryTime = &_ccnxContentObjectFacadeV1_HasExpiryTime,
+
+ .getPathLabel = &_ccnxContentObjectFacadeV1_GetPathLabel,
+ .setPathLabel = &_ccnxContentObjectFacadeV1_SetPathLabel,
+ .hasPathLabel = &_ccnxContentObjectFacadeV1_HasPathLabel,
+
+ .toString = &_ccnxContentObjectFacadeV1_ToString,
+ .display = &_ccnxContentObjectFacadeV1_Display,
+ .equals = &_ccnxContentObjectFacadeV1_Equals,
+
+ .assertValid = &_assertInvariants,
+};
diff --git a/libccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.h
new file mode 100755
index 00000000..d95c56b3
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectFacadeV1.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_ContentObjectFacade.h
+ * @ingroup ContentObject
+ * @brief This facade is used to access fields within an RTA-encoded content object.
+ *
+ * Content objects are encoded and transmitted through the transport stack before being sent over the wire.
+ * This facade acts an interface to this transport-specific encoding of the content object. It enables
+ * the user to directly access fields within the content object without having any knowledge about the
+ * particular schema-specific encoding.
+ *
+ */
+#ifndef libccnx_ccnx_ContentObjectFacadeV1_h
+#define libccnx_ccnx_ContentObjectFacadeV1_h
+
+#include <ccnx/common/internal/ccnx_ContentObjectInterface.h>
+
+extern CCNxContentObjectInterface CCNxContentObjectFacadeV1_Implementation;
+
+#endif // libccnx_ccnx_ContentObjectFacadeV1_h
diff --git a/libccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.c b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.c
new file mode 100755
index 00000000..ac33c2ab
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/internal/ccnx_ContentObjectInterface.h>
+
+
+CCNxContentObjectInterface *
+ccnxContentObjectInterface_GetInterface(const CCNxTlvDictionary *dictionary)
+{
+ assertTrue(ccnxTlvDictionary_IsContentObject(dictionary), "Expected a ContentObject");
+
+ CCNxContentObjectInterface *impl = (CCNxContentObjectInterface *) ccnxTlvDictionary_GetMessageInterface(dictionary);
+
+ if (impl == NULL) {
+ // If we're here, we need to update the implementation pointer.
+ // Figure out what the typeImplementation should be, based on the attributes we know.
+ int schemaVersion = ccnxTlvDictionary_GetSchemaVersion(dictionary);
+
+ switch (schemaVersion) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ impl = &CCNxContentObjectFacadeV1_Implementation;
+ break;
+ default:
+ trapUnexpectedState("Unknown SchemaVersion encountered in ccnxContentObjectInterface_GetInterface()");
+ break;
+ }
+
+ if (impl != NULL) {
+ // The cast to (CCNxTlvDictionary *) is to break the const.
+ ccnxTlvDictionary_SetMessageInterface((CCNxTlvDictionary *) dictionary, (CCNxMessageInterface *) impl);
+ }
+ }
+
+ return impl;
+}
diff --git a/libccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.h b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.h
new file mode 100644
index 00000000..c2d67680
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_ContentObjectInterface.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @brief A structure of functions representing a ContentObject implementation.
+ *
+ * The underlying implementation should support the CCNxContentObject API.
+ *
+ */
+
+#ifndef CCNx_Common_ccnx_internal_ContentObjectInterface_h
+#define CCNx_Common_ccnx_internal_ContentObjectInterface_h
+
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/common/ccnx_KeyLocator.h>
+#include <ccnx/common/ccnx_PayloadType.h>
+
+typedef struct ccnx_contentobject_interface {
+ char *description; // A human-readable label for this implementation
+
+ /** @see ccnxContentObject_CreateWithNameAndPayload */
+ CCNxTlvDictionary *(*createWithNameAndPayload)(const CCNxName * contentName,
+ const CCNxPayloadType contentType,
+ const PARCBuffer * payload);
+
+ /** @see ccnxContentObject_CreateWithPayload */
+ CCNxTlvDictionary *(*createWithPayload)(const CCNxPayloadType contentType,
+ const PARCBuffer * payload);
+
+ /** @see ccnxContentObject_GetName */
+ CCNxName *(*getName)(const CCNxTlvDictionary * dict);
+
+ /** @see ccnxContentObject_SetSignature */
+ bool (*setSignature)(CCNxTlvDictionary *dict,
+ const PARCBuffer *keyId,
+ const PARCSignature *signature,
+ const CCNxKeyLocator *keyLocator);
+
+ /** @see ccnxContentObject_GetKeyId */
+ PARCBuffer *(*getKeyId)(const CCNxTlvDictionary * dict);
+
+ /** @see ccnxContentObject_GetPayload */
+ PARCBuffer *(*getPayload)(const CCNxTlvDictionary * dict);
+
+ /** @see ccnxContentObject_GetPayloadType */
+ CCNxPayloadType (*getPayloadType)(const CCNxTlvDictionary *dict);
+
+ /** @see ccnxContentObject_SetPayload */
+ bool (*setPayload)(CCNxTlvDictionary *dict, CCNxPayloadType payloadType, const PARCBuffer *payload);
+
+ /** @see ccnxContentObject_SetFinalChunkNumber */
+ bool (*setFinalChunkNumber)(CCNxTlvDictionary *dict, const uint64_t finalChunkNumber);
+
+ /** @see ccnxContentObject_GetFinalChunkNumber */
+ uint64_t (*getFinalChunkNumber)(const CCNxTlvDictionary *dict);
+
+ /** @see ccnxContentObject_HasFinalChunkNumber */
+ bool (*hasFinalChunkNumber)(const CCNxTlvDictionary *dict);
+
+ /** @see ccnxContentObject_SetExpiryTime */
+ bool (*setExpiryTime)(CCNxTlvDictionary *dict, const uint64_t expiryTime);
+
+ /** @see ccnxContentObject_GetExpiryTime */
+ uint64_t (*getExpiryTime)(const CCNxTlvDictionary *dict);
+
+ /** @see ccnxContentObject_HasExpiryTime */
+ bool (*hasExpiryTime)(const CCNxTlvDictionary *dict);
+
+ /** @see ccnxContentObject_Equals */
+ bool (*equals)(const CCNxTlvDictionary *objectA, const CCNxTlvDictionary *objectB);
+
+ /** @see ccnxContentObject_AssertValid */
+ void (*assertValid)(const CCNxTlvDictionary *dict);
+
+ /** @see ccnxContentObject_ToString */
+ char *(*toString)(const CCNxTlvDictionary * dict);
+
+ /** @see ccnxContentObject_CreateWithPayload */
+ void (*display)(const CCNxTlvDictionary *interestDictionary, size_t indentation);
+
+ bool (*setPathLabel)(CCNxTlvDictionary *dict, const uint64_t pathLabel);
+ uint64_t (*getPathLabel)(const CCNxTlvDictionary *dict);
+ bool (*hasPathLabel)(const CCNxTlvDictionary *dict);
+} CCNxContentObjectInterface;
+
+/**
+ * The SchemaV1 ContentObject implementaton
+ */
+extern CCNxContentObjectInterface CCNxContentObjectFacadeV1_Implementation;
+
+/**
+ * Given a CCNxTlvDictionary representing a CCNxContentObject, return the address of the CCNxContentObjectInterface
+ * instance that should be used to access the ContentObject. This will also update the CCNxTlvDictionary's implementation
+ * pointer for future references.
+ *
+ * @param contentDictionary - a {@link CCNxTlvDictionary} representing a CCNxContentObject.
+ * @return the address of the `CCNxContentObjectInterface` instance that should be used to access the CCNxContentObject.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+ *
+ * CCNxContentObject *contentObjectV0 =
+ * ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV0_Implementation,
+ * name,
+ * CCNxPayloadType_DATA,
+ * NULL);
+ *
+ * CCNxContentObject *contentObjectV1 =
+ * ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ * name,
+ * CCNxPayloadType_DATA,
+ * NULL);
+ *
+ * assertTrue(ccnxContentObjectInterface_GetInterface(contentObjectV0) == &CCNxContentObjectFacadeV0_Implementation,
+ * "Expected V0 Implementation");
+ *
+ * assertTrue(ccnxContentObjectInterface_GetInterface(contentObjectV1) == &CCNxContentObjectFacadeV1_Implementation,
+ * "Expected V1 Implementation");
+ *
+ * ccnxName_Release(&name);
+ * ccnxContentObject_Release(&contentObjectV0);
+ * ccnxContentObject_Release(&contentObjectV1);
+ * }
+ * @endcode
+ */
+CCNxContentObjectInterface *ccnxContentObjectInterface_GetInterface(const CCNxTlvDictionary *contentDictionary);
+#endif
diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestDefault.c b/libccnx-common/ccnx/common/internal/ccnx_InterestDefault.c
new file mode 100755
index 00000000..a0bb134a
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_InterestDefault.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include "ccnx_InterestDefault.h"
+
+const uint32_t CCNxInterestDefault_LifetimeMilliseconds = -1;
+const uint32_t CCNxInterestDefault_HopLimit = 255;
+const CCNxInterestPayloadIdMethod CCNxInterestDefault_PayloadIdMethod = CCNxInterestPayloadIdMethod_App;
+
diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestDefault.h b/libccnx-common/ccnx/common/internal/ccnx_InterestDefault.h
new file mode 100755
index 00000000..ebfc859a
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_InterestDefault.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_InterestDefault.h
+ * @brief Default values for various fields in an Interest
+ *
+ * Declares several constants that may be used when creating an Interest with default values.
+ * These may be used in a V0 or V1 Interest.
+ *
+ */
+
+#ifndef __CCNx_Common__ccnx_InterestDefault__
+#define __CCNx_Common__ccnx_InterestDefault__
+
+#include <inttypes.h>
+#include <ccnx/common/internal/ccnx_InterestPayloadIdMethod.h>
+
+/**
+ * May be used in calls to create an Interest with the default lifetime. An Interest with
+ * the default lifetime does not encode the field in the wire format.
+ */
+extern const uint32_t CCNxInterestDefault_LifetimeMilliseconds;
+
+/**
+ * May be used in calls to create an Interest with the default hoplimit.
+ */
+extern const uint32_t CCNxInterestDefault_HopLimit;
+
+/**
+ * May be used in calls to create an Interest with the default payload id method.
+ *
+ * The PayloadIdMethod is a field inside the Interest that describes how the InterestPayloadId in the Name
+ * was calcuated.
+ */
+extern const CCNxInterestPayloadIdMethod CCNxInterestDefault_PayloadIdMethod;
+
+#endif /* defined(__CCNx_Common__ccnx_InterestDefault__) */
diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.c
new file mode 100644
index 00000000..5fca3cea
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/internal/ccnx_InterestFacadeV1.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+#include <ccnx/common/internal/ccnx_InterestDefault.h>
+
+
+// =====================
+
+static void
+_assertInvariants(const CCNxTlvDictionary *interestDictionary)
+{
+ assertNotNull(interestDictionary, "Dictionary is null");
+ assertTrue((ccnxTlvDictionary_IsInterest(interestDictionary) ||
+ ccnxTlvDictionary_IsInterestReturn(interestDictionary)), "Dictionary is not an interest");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(interestDictionary) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Dictionary is wrong schema Interest, got %d expected %d",
+ ccnxTlvDictionary_GetSchemaVersion(interestDictionary), CCNxTlvDictionary_SchemaVersion_V1);
+}
+
+static uint32_t
+_fetchUint32(const CCNxTlvDictionary *interestDictionary, uint32_t key, uint32_t defaultValue)
+{
+ if (ccnxTlvDictionary_IsValueInteger(interestDictionary, key)) {
+ return (uint32_t) ccnxTlvDictionary_GetInteger(interestDictionary, key);
+ }
+ return defaultValue;
+}
+
+static bool
+_ccnxInterestFacadeV1_SetContentObjectHashRestriction(CCNxTlvDictionary *interestDictionary, const PARCBuffer *contentObjectHash)
+{
+ _assertInvariants(interestDictionary);
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, contentObjectHash);
+ bool result = ccnxTlvDictionary_PutObject(interestDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION,
+ hash);
+ parcCryptoHash_Release(&hash);
+ return result;
+}
+
+// forward declaration. Body below, in Getters.
+static CCNxName *
+_ccnxInterestFacadeV1_GetName(const CCNxTlvDictionary *interestDictionary);
+
+static bool
+_ccnxInterestFacadeV1_SetPayloadWithId(CCNxTlvDictionary *interestDictionary, const PARCBuffer *payload, const CCNxInterestPayloadId *payloadId)
+{
+ bool result = false;
+
+ if (payload) {
+ result = ccnxTlvDictionary_PutBuffer(interestDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, payload);
+ if (payloadId != NULL) {
+ CCNxName *name = _ccnxInterestFacadeV1_GetName(interestDictionary);
+ ccnxName_Append(name, ccnxInterestPayloadId_GetNameSegment(payloadId));
+ }
+ }
+ return result;
+}
+
+static bool
+_ccnxInterestFacadeV1_SetPayloadAndId(CCNxTlvDictionary *interestDictionary, const PARCBuffer *payload)
+{
+ bool result = false;
+
+ if (payload) {
+ CCNxInterestPayloadId *pid = ccnxInterestPayloadId_CreateAsSHA256Hash(payload);
+ _ccnxInterestFacadeV1_SetPayloadWithId(interestDictionary, payload, pid);
+ ccnxInterestPayloadId_Release(&pid);
+ }
+ return result;
+}
+
+static bool
+_ccnxInterestFacadeV1_SetPayload(CCNxTlvDictionary *interestDictionary, const PARCBuffer *payload)
+{
+ bool result = false;
+
+ if (payload) {
+ _ccnxInterestFacadeV1_SetPayloadWithId(interestDictionary, payload, NULL);
+ }
+ return result;
+}
+
+static bool
+_ccnxInterestFacadeV1_SetLifetime(CCNxTlvDictionary *interestDictionary, uint32_t lifetimeInMillis)
+{
+ return ccnxTlvDictionary_PutInteger(interestDictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime, lifetimeInMillis);
+}
+
+static bool
+_ccnxInterestFacadeV1_SetKeyIdRestriction(CCNxTlvDictionary *interestDictionary, const PARCBuffer *keyId)
+{
+ _assertInvariants(interestDictionary);
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, keyId);
+ bool result = ccnxTlvDictionary_PutObject(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION, hash);
+ parcCryptoHash_Release(&hash);
+ return result;
+}
+
+static bool
+_ccnxInterestFacadeV1_SetHopLimit(CCNxTlvDictionary *interestDictionary, uint32_t hopLimit)
+{
+ _assertInvariants(interestDictionary);
+ return ccnxTlvDictionary_PutInteger(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, hopLimit);
+}
+
+// =====================
+// Getters
+
+static CCNxName *
+_ccnxInterestFacadeV1_GetName(const CCNxTlvDictionary *interestDictionary)
+{
+ int key = CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME;
+ _assertInvariants(interestDictionary);
+ if (ccnxTlvDictionary_IsValueName(interestDictionary, key)) {
+ return ccnxTlvDictionary_GetName(interestDictionary, key);
+ }
+ return NULL;
+}
+
+static uint32_t
+_ccnxInterestFacadeV1_GetLifetime(const CCNxTlvDictionary *interestDictionary)
+{
+ _assertInvariants(interestDictionary);
+ return _fetchUint32(interestDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime, CCNxInterestDefault_LifetimeMilliseconds);
+}
+
+static PARCBuffer *
+_ccnxInterestFacadeV1_GetKeyIdRestriction(const CCNxTlvDictionary *interestDictionary)
+{
+ _assertInvariants(interestDictionary);
+ PARCCryptoHash *hash = ccnxTlvDictionary_GetObject(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION);
+ if (hash != NULL) {
+ return parcCryptoHash_GetDigest(hash);
+ } else {
+ return NULL;
+ }
+}
+
+static PARCBuffer *
+_ccnxInterestFacadeV1_GetContentObjectHashRestriction(const CCNxTlvDictionary *interestDictionary)
+{
+ _assertInvariants(interestDictionary);
+ PARCCryptoHash *hash = ccnxTlvDictionary_GetObject(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION);
+ if (hash != NULL) {
+ return parcCryptoHash_GetDigest(hash);
+ } else {
+ return NULL;
+ }
+}
+
+static PARCBuffer *
+_ccnxInterestFacadeV1_GetPayload(const CCNxTlvDictionary *interestDictionary)
+{
+ _assertInvariants(interestDictionary);
+ return ccnxTlvDictionary_GetBuffer(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+}
+
+static uint32_t
+_ccnxInterestFacadeV1_GetHopLimit(const CCNxTlvDictionary *interestDictionary)
+{
+ _assertInvariants(interestDictionary);
+ return _fetchUint32(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, CCNxInterestDefault_HopLimit);
+}
+
+// =====================
+// Miscellaneous
+
+static void
+_ccnxInterestFacadeV1_AssertValid(const CCNxTlvDictionary *interestDictionary)
+{
+ _assertInvariants(interestDictionary);
+ assertTrue(ccnxTlvDictionary_IsValueName(interestDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME), "Name field is not a name");
+}
+
+static bool
+_ccnxInterestFacadeV1_Equals(const CCNxTlvDictionary *a, const CCNxTlvDictionary *b)
+{
+ return ccnxTlvDictionary_Equals(a, b);
+}
+
+static void
+_ccnxInterestFacadeV1_Display(const CCNxTlvDictionary *interestDictionary, size_t indentation)
+{
+ _assertInvariants(interestDictionary);
+ ccnxTlvDictionary_Display(interestDictionary, (unsigned) indentation);
+}
+
+
+// =====================
+// Creation
+
+static CCNxTlvDictionary *
+_ccnxInterestFacadeV1_Create(const CCNxName *name, // required
+ const uint32_t lifetimeMilliseconds, // may use DefaultLimetimeMilliseconds
+ const PARCBuffer *keyId, // may be NULL
+ const PARCBuffer *contentObjectHash, // may be NULL
+ const uint32_t hopLimit) // may be DefaultHopLimit
+{
+ assertNotNull(name, "Parameter name must be non-null");
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ if (dictionary) {
+ ccnxTlvDictionary_PutName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name);
+
+ if (lifetimeMilliseconds != CCNxInterestDefault_LifetimeMilliseconds) {
+ _ccnxInterestFacadeV1_SetLifetime(dictionary, lifetimeMilliseconds);
+ }
+
+ if (keyId) {
+ _ccnxInterestFacadeV1_SetKeyIdRestriction(dictionary, keyId);
+ }
+
+ if (contentObjectHash) {
+ _ccnxInterestFacadeV1_SetContentObjectHashRestriction(dictionary, contentObjectHash);
+ }
+
+ if (hopLimit != CCNxInterestDefault_HopLimit) {
+ _ccnxInterestFacadeV1_SetHopLimit(dictionary, hopLimit);
+ }
+ } else {
+ trapOutOfMemory("Could not allocate an Interest");
+ }
+
+ return dictionary;
+}
+
+static CCNxTlvDictionary *
+_ccnxInterestFacadeV1_CreateSimple(const CCNxName *name)
+{
+ return _ccnxInterestFacadeV1_Create(name,
+ CCNxInterestDefault_LifetimeMilliseconds,
+ NULL, // keyid
+ NULL, // content object hash
+ CCNxInterestDefault_HopLimit);
+}
+
+CCNxInterestInterface CCNxInterestFacadeV1_Implementation = {
+ .description = "CCNxInterestFacadeV1_Implementation",
+
+ .createSimple = &_ccnxInterestFacadeV1_CreateSimple,
+ .create = &_ccnxInterestFacadeV1_Create,
+
+ .getName = &_ccnxInterestFacadeV1_GetName,
+
+ .setContentObjectHashRestriction = &_ccnxInterestFacadeV1_SetContentObjectHashRestriction,
+ .getContentObjectHashRestriction = &_ccnxInterestFacadeV1_GetContentObjectHashRestriction,
+
+ .setLifetime = &_ccnxInterestFacadeV1_SetLifetime,
+ .getLifetime = &_ccnxInterestFacadeV1_GetLifetime,
+
+ .setKeyIdRestriction = &_ccnxInterestFacadeV1_SetKeyIdRestriction,
+ .getKeyIdRestriction = &_ccnxInterestFacadeV1_GetKeyIdRestriction,
+
+ .getHopLimit = &_ccnxInterestFacadeV1_GetHopLimit,
+ .setHopLimit = &_ccnxInterestFacadeV1_SetHopLimit,
+
+ .getPayload = &_ccnxInterestFacadeV1_GetPayload,
+
+ .setPayload = &_ccnxInterestFacadeV1_SetPayload,
+ .setPayloadAndId = &_ccnxInterestFacadeV1_SetPayloadAndId,
+ .setPayloadWithId = &_ccnxInterestFacadeV1_SetPayloadWithId,
+
+ .toString = NULL,
+ .equals = &_ccnxInterestFacadeV1_Equals,
+ .display = &_ccnxInterestFacadeV1_Display,
+
+ .assertValid = &_ccnxInterestFacadeV1_AssertValid,
+};
diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.h
new file mode 100755
index 00000000..29739f2c
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_InterestFacadeV1.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_InterestFacadeV1.h
+ * @ingroup Interest
+ * @brief A CCN Interest facade for an Interest over a CCNxTlvDictionary, using v1 schema.
+ *
+ */
+#ifndef libccnx_ccnx_InterestFacadeV1_h
+#define libccnx_ccnx_InterestFacadeV1_h
+
+#include <ccnx/common/internal/ccnx_InterestInterface.h>
+
+extern CCNxInterestInterface CCNxInterestFacadeV1_Implementation;
+
+#endif // libccnx_ccnx_InterestFacadeV1_h
diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestInterface.c b/libccnx-common/ccnx/common/internal/ccnx_InterestInterface.c
new file mode 100755
index 00000000..a507d69d
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_InterestInterface.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/internal/ccnx_InterestInterface.h>
+
+CCNxInterestInterface *
+ccnxInterestInterface_GetInterface(const CCNxTlvDictionary *dictionary)
+{
+ assertTrue((ccnxTlvDictionary_IsInterest(dictionary) ||
+ ccnxTlvDictionary_IsInterestReturn(dictionary)), "Expected an Interest or InterestReturn");
+
+ CCNxInterestInterface *impl = (CCNxInterestInterface *) ccnxTlvDictionary_GetMessageInterface(dictionary);
+
+ if (impl == NULL) {
+ // If we're here, we need to update the interface pointer.
+ // Figure out what the typeInterface should be, based on the attributes we know.
+ int schemaVersion = ccnxTlvDictionary_GetSchemaVersion(dictionary);
+
+ switch (schemaVersion) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ impl = &CCNxInterestFacadeV1_Implementation;
+ break;
+ default:
+ trapUnexpectedState("Unknown SchemaVersion encountered in ccnxInterestInterface_GetInterface()");
+ break;
+ }
+
+ if (impl == NULL) {
+ // The cast to (CCNxTlvDictionary *) is to break the const.
+ ccnxTlvDictionary_SetMessageInterface((CCNxTlvDictionary *) dictionary, (CCNxMessageInterface *) impl);
+ }
+ }
+ return impl;
+}
+
diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestInterface.h b/libccnx-common/ccnx/common/internal/ccnx_InterestInterface.h
new file mode 100644
index 00000000..bb78dfc3
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_InterestInterface.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @brief A structure of functions representing an Interest implementation.
+ *
+ * The underlying implementation should support the CCNxInterest API.
+ *
+ */
+
+#ifndef CCNx_Common_ccnx_internal_InterestInterface_h
+#define CCNx_Common_ccnx_internal_InterestInterface_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+#include <ccnx/common/internal/ccnx_InterestPayloadIdMethod.h>
+#include <ccnx/common/ccnx_InterestPayloadId.h>
+
+typedef struct ccnx_interest_interface {
+ /** A human-readable label for this implementation */
+ char *description;
+
+ /** @see ccnxInterest_Create */
+ CCNxTlvDictionary *(*create)(const CCNxName * name, // required
+ const uint32_t lifetimeMilliseconds, // may use DefaultLimetimeMilliseconds
+ const PARCBuffer * keyId, // may be NULL
+ const PARCBuffer * contentObjectHash, // may be NULL
+ const uint32_t hopLimit);
+
+ /** @see ccnxInterest_CreateSimple */
+ CCNxTlvDictionary *(*createSimple)(const CCNxName * name);
+
+ /** @see ccnxInterest_GetName */
+ CCNxName *(*getName)(const CCNxTlvDictionary * dict);
+
+ /** @see ccnxInterest_SetLifetime */
+ bool (*setLifetime)(CCNxTlvDictionary *dict, uint32_t lifetime);
+
+ /** @see ccnxInterest_GetLifetime */
+ uint32_t (*getLifetime)(const CCNxTlvDictionary *dict);
+
+ /** @see ccnxInterest_SetHopLimit */
+ bool (*setHopLimit)(CCNxTlvDictionary *dict, uint32_t hopLimit);
+
+ /** @see ccnxInterest_GetHopLimit */
+ uint32_t (*getHopLimit)(const CCNxTlvDictionary *dict);
+
+ /** @see ccnxInterest_SetKeyIdRestriction */
+ bool (*setKeyIdRestriction)(CCNxTlvDictionary *dict, const PARCBuffer *keyId);
+
+ /** @see ccnxInterest_GetKeyIdRestriction */
+ PARCBuffer *(*getKeyIdRestriction)(const CCNxTlvDictionary * dict);
+
+ /** @see ccnxInterest_SetPayload */
+ bool (*setPayload)(CCNxTlvDictionary *dict, const PARCBuffer *payload);
+
+ /** @see ccnxInterest_SetPayloadAndId */
+ bool (*setPayloadAndId)(CCNxTlvDictionary *dict, const PARCBuffer *payload);
+
+ /** @see ccnxInterest_SetPayloadWithId */
+ bool (*setPayloadWithId)(CCNxTlvDictionary *dict, const PARCBuffer *payload, const CCNxInterestPayloadId *id);
+
+ /** @see ccnxInterest_GetPayload */
+ PARCBuffer *(*getPayload)(const CCNxTlvDictionary * dict);
+
+ /** @see ccnxInterest_SetContentObjectHashRestriction */
+ bool (*setContentObjectHashRestriction)(CCNxTlvDictionary *dict, const PARCBuffer *contentObjectHash);
+
+ /** @see ccnxInterest_GetContentObjectHashRestriction */
+ PARCBuffer *(*getContentObjectHashRestriction)(const CCNxTlvDictionary * dict);
+
+ /** @see ccnxInterest_Equals */
+ bool (*equals)(const CCNxTlvDictionary *objectA, const CCNxTlvDictionary *objectB);
+ /** @see ccnxInterest_AssertValid */
+ void (*assertValid)(const CCNxTlvDictionary *dict);
+
+ /** @see ccnxInterest_ToString */
+ char *(*toString)(const CCNxTlvDictionary * dict);
+ /** @see ccnxInterest_Display */
+ void (*display)(const CCNxTlvDictionary *interestDictionary, size_t indentation);
+} CCNxInterestInterface;
+
+
+/**
+ * The SchemaV1 Interest implementaton
+ */
+extern CCNxInterestInterface CCNxInterestFacadeV1_Implementation;
+
+/**
+ * Given a CCNxTlvDictionary representing a CCNxInterest, return the address of the CCNxInterestInterface
+ * instance that should be used to access the Interest. This will also update the CCNxTlvDictionary's interface
+ * pointer for future references.
+ *
+ * @param interestDictionary - a {@link CCNxTlvDictionary} representing a CCNxInterest.
+ * @return the address of the `CCNxContentObjectInterface` instance that should be used to access the CCNxInterest.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+ *
+ * CCNxInterest *interestV1 =
+ * ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ * name,
+ * CCNxInterestDefault_LifetimeMilliseconds,
+ * NULL,
+ * NULL,
+ * CCNxInterestDefault_HopLimit);
+ *
+ * assertTrue(ccnxInterestInterface_GetInterface(interestV1) == &CCNxInterestFacadeV1_Implementation,
+ * "Expected V1 Implementation");
+ *
+ * ccnxName_Release(&name);
+ * ccnxInterest_Release(&interestV1);
+ * } * @endcode
+ */
+CCNxInterestInterface *ccnxInterestInterface_GetInterface(const CCNxTlvDictionary *interestDictionary);
+#endif
diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestPayloadIdMethod.h b/libccnx-common/ccnx/common/internal/ccnx_InterestPayloadIdMethod.h
new file mode 100755
index 00000000..a29ddb9e
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_InterestPayloadIdMethod.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#ifndef CCNx_Common_ccnx_InterestPayloadIdMethod_h
+#define CCNx_Common_ccnx_InterestPayloadIdMethod_h
+
+typedef enum {
+ CCNxInterestPayloadIdMethod_App = 0,
+ CCNxInterestPayloadIdMethod_Nonce = 1,
+ CCNxInterestPayloadIdMethod_RFC6920 = 2
+} CCNxInterestPayloadIdMethod;
+
+#endif
diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.c
new file mode 100755
index 00000000..80c1b718
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/internal/ccnx_InterestReturnFacadeV1.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+// =====================
+
+static void
+_assertInvariants(const CCNxTlvDictionary *interestDictionary)
+{
+ assertNotNull(interestDictionary, "Dictionary is null");
+ assertTrue(ccnxTlvDictionary_IsInterestReturn(interestDictionary), "Dictionary is not an interest");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(interestDictionary) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Dictionary is wrong schema InterestReturn, got %d expected %d",
+ ccnxTlvDictionary_GetSchemaVersion(interestDictionary), CCNxTlvDictionary_SchemaVersion_V1);
+}
+
+static uint32_t
+_fetchUint32(const CCNxTlvDictionary *interestDictionary, uint32_t key, uint32_t defaultValue)
+{
+ if (ccnxTlvDictionary_IsValueInteger(interestDictionary, key)) {
+ return (uint32_t) ccnxTlvDictionary_GetInteger(interestDictionary, key);
+ }
+ return defaultValue;
+}
+
+// =====================
+// Creation
+
+static CCNxTlvDictionary *
+_ccnxInterestReturnFacadeV1_Create(
+ const CCNxInterest *interest,
+ CCNxInterestReturn_ReturnCode code)
+{
+ assertNotNull(interest, "Parameter name must be non-null");
+
+ assertTrue(ccnxInterestInterface_GetInterface(interest) == &CCNxInterestFacadeV1_Implementation,
+ "Non-V1 CCNxInterest passed to V1 ccnxInterestReturn_Create()");
+
+ CCNxInterestReturnFacadeV1_Implementation.interestImpl = CCNxInterestFacadeV1_Implementation;
+
+
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_ShallowCopy(interest);
+
+ //Add InterestReturn specific stuff
+ ccnxTlvDictionary_SetMessageType_InterestReturn(dictionary,
+ CCNxTlvDictionary_SchemaVersion_V1);
+
+ ccnxTlvDictionary_PutInteger(dictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode,
+ code);
+
+ return dictionary;
+}
+
+static void
+_ccnxInterestReturnFacadeV1_AssertValid(const CCNxTlvDictionary *interestDictionary)
+{
+ _assertInvariants(interestDictionary);
+ assertTrue(ccnxTlvDictionary_IsValueName(interestDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME), "Name field is not a name");
+}
+
+static CCNxInterestReturn_ReturnCode
+_ccnxInterestReturnFacadeV1_GetReturnCode(const CCNxTlvDictionary *interestDictionary)
+{
+ _assertInvariants(interestDictionary);
+ CCNxInterestReturn_ReturnCode code = _fetchUint32(interestDictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode,
+ 0);
+ assertTrue(((code > 0) && (code < CCNxInterestReturn_ReturnCode_END)), "InterestReturn ReturnCode is out of ranage");
+
+ return code;
+}
+
+CCNxInterestReturnInterface CCNxInterestReturnFacadeV1_Implementation = {
+ .Create = &_ccnxInterestReturnFacadeV1_Create,
+ .AssertValid = &_ccnxInterestReturnFacadeV1_AssertValid,
+ .GetReturnCode = &_ccnxInterestReturnFacadeV1_GetReturnCode,
+};
diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.h
new file mode 100755
index 00000000..e8aa0e37
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnFacadeV1.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_InterestReturnFacadeV1.h
+ * @ingroup InterestReturn
+ * @brief A CCN InterestReturn facade over a CCNxTlvDictionary, using v1 schema.
+ *
+ */
+#ifndef libccnx_ccnx_InterestReturnFacadeV1_h
+#define libccnx_ccnx_InterestReturnFacadeV1_h
+
+#include <ccnx/common/internal/ccnx_InterestReturnInterface.h>
+
+extern CCNxInterestReturnInterface CCNxInterestReturnFacadeV1_Implementation;
+
+#endif // libccnx_ccnx_InterestReturnFacadeV1_h
diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.c b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.c
new file mode 100755
index 00000000..2c9aa111
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <ccnx/common/internal/ccnx_InterestReturnInterface.h>
+
+#include <LongBow/runtime.h>
+
+CCNxInterestReturnInterface *
+ccnxInterestReturnInterface_GetInterface(const CCNxTlvDictionary *dictionary)
+{
+ assertTrue(ccnxTlvDictionary_IsInterestReturn(dictionary), "Expected an InterestReturn");
+
+ CCNxInterestReturnInterface *impl = ccnxTlvDictionary_GetMessageInterface(dictionary);
+
+ if (!impl) {
+ // If we're here, we need to update the interface pointer. Break the const.
+ // We're not changing data values, just initializing the Interface pointer.
+
+ // Figure out what the typeInterface should be, based on the attributes we know.
+ int schemaVersion = ccnxTlvDictionary_GetSchemaVersion(dictionary);
+
+ switch (schemaVersion) {
+ case CCNxTlvDictionary_SchemaVersion_V0:
+ trapUnexpectedState("ccnxInterestReturnInterface_GetInterface() not implemented for V0");
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ impl = &CCNxInterestReturnFacadeV1_Implementation;
+ break;
+ default:
+ trapUnexpectedState("Unknown SchemaVersion encountered in ccnxInterestReturnInterface_GetInterface()");
+ break;
+ }
+
+ if (impl) {
+ ccnxTlvDictionary_SetMessageInterface((CCNxTlvDictionary *) dictionary, impl); // break the const.
+ }
+ }
+
+ return impl;
+}
+
diff --git a/libccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.h b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.h
new file mode 100644
index 00000000..3f36fb90
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_InterestReturnInterface.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef CCNx_Common_ccnx_internal_InterestReturnInterface_h
+#define CCNx_Common_ccnx_internal_InterestReturnInterface_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+#include <ccnx/common/ccnx_Interest.h>
+
+
+typedef struct ccnx_interest_return_interface {
+ CCNxInterestInterface interestImpl;
+
+ CCNxTlvDictionary *(*Create)(const CCNxInterest * interest, CCNxInterestReturn_ReturnCode code);
+
+ bool (*Equals)(const CCNxTlvDictionary *objectA, const CCNxTlvDictionary *objectB);
+ void (*AssertValid)(const CCNxTlvDictionary *dict);
+ char *(*ToString)(const CCNxTlvDictionary * dict);
+
+ uint32_t (*GetReturnCode)(const CCNxTlvDictionary *dict);
+} CCNxInterestReturnInterface;
+
+extern CCNxInterestReturnInterface CCNxInterestReturnFacadeV1_Implementation;
+
+/**
+ * Given a CCNxTlvDictionary representing a CCNxInterestReturn, return the address of the CCNxInterestReturnInterface
+ * instance that should be used to access the InterestReturn.
+ *
+ * @param interestDictionary - a {@link CCNxTlvDictionary} representing a CCNxInterestReturn.
+ * @return the address of the `CCNxInterestReturnInterface` instance that should be used to access the CCNxInterestReturn.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * CCNxInterest *interest = ...;
+ * CCNxInterestReturn *interestReturn =
+ * ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_NoRoute);
+ *
+ * //V1 test
+ * if (ccnxInterestReturnInterface_GetInterface(interestReturn) == &CCNxInterestReturnFacadeV1_Implementation) {
+ * printf("Using a V1 CCNxInterestReturnInterface \n");
+ * }
+ *
+ * ...
+ *
+ * ccnxInterestReturn_Release(&interestReturn);
+ * } * @endcode
+ */
+CCNxInterestReturnInterface *ccnxInterestReturnInterface_GetInterface(const CCNxTlvDictionary *interestDictionary);
+#endif
diff --git a/libccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.c
new file mode 100644
index 00000000..e419d18e
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_JSON.h>
+
+#include <ccnx/common/ccnx_Manifest.h>
+#include <ccnx/common/internal/ccnx_ManifestInterface.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+static size_t _ccnxManifestFacadeV1_GetNumberOfHashGroups(const CCNxTlvDictionary *dict);
+
+static CCNxTlvDictionary *
+_ccnxManifestFacadeV1_Create(const CCNxName *name)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateManifest();
+
+ if (dictionary != NULL) {
+ if (name != NULL) {
+ ccnxTlvDictionary_PutName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name);
+ }
+ } else {
+ trapOutOfMemory("Could not allocate an Manifest");
+ }
+
+ return dictionary;
+}
+
+static const CCNxName *
+_ccnxManifestFacadeV1_GetName(const CCNxTlvDictionary *dict)
+{
+ return ccnxTlvDictionary_GetName(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+}
+
+static void
+_ccnxManifestFacadeV1_AddHashGroup(CCNxTlvDictionary *dict, const CCNxManifestHashGroup *group)
+{
+ PARCJSON *json = ccnxManifestHashGroup_ToJson(group);
+ size_t numGroups = _ccnxManifestFacadeV1_GetNumberOfHashGroups(dict);
+
+ char *jsonString = parcJSON_ToString(json);
+ PARCBuffer *buffer = parcBuffer_AllocateCString(jsonString);
+ parcMemory_Deallocate(&jsonString);
+ parcJSON_Release(&json);
+
+ ccnxTlvDictionary_PutListBuffer(dict, CCNxCodecSchemaV1TlvDictionary_Lists_HASH_GROUP_LIST, (uint32_t) numGroups, buffer);
+ parcBuffer_Release(&buffer);
+}
+
+static CCNxManifestHashGroup *
+_ccnxManifestFacadeV1_GetHashGroup(const CCNxTlvDictionary *dict, size_t index)
+{
+ PARCBuffer *buffer = NULL;
+ uint32_t key;
+ ccnxTlvDictionary_ListGetByPosition(dict, CCNxCodecSchemaV1TlvDictionary_Lists_HASH_GROUP_LIST, index, &buffer, &key);
+
+ char *jsonString = parcBuffer_ToString(buffer);
+ PARCJSON *json = parcJSON_ParseString(jsonString);
+ parcMemory_Deallocate(&jsonString);
+
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_CreateFromJson(json);
+ parcJSON_Release(&json);
+
+ return group;
+}
+
+static size_t
+_ccnxManifestFacadeV1_GetNumberOfHashGroups(const CCNxTlvDictionary *dict)
+{
+ size_t numHashGroups = ccnxTlvDictionary_ListSize(dict, CCNxCodecSchemaV1TlvDictionary_Lists_HASH_GROUP_LIST);
+ return numHashGroups;
+}
+
+static bool
+_ccnxManifestFacadeV1_Equals(const CCNxTlvDictionary *dictA, const CCNxTlvDictionary *dictB)
+{
+ if (dictA == dictB) {
+ return true;
+ }
+ if (dictA == NULL || dictB == NULL) {
+ return false;
+ }
+
+ if (ccnxName_Equals(_ccnxManifestFacadeV1_GetName(dictA), _ccnxManifestFacadeV1_GetName(dictB))) {
+ if (_ccnxManifestFacadeV1_GetNumberOfHashGroups(dictA) == _ccnxManifestFacadeV1_GetNumberOfHashGroups(dictB)) {
+ for (size_t i = 0; i < _ccnxManifestFacadeV1_GetNumberOfHashGroups(dictA); i++) {
+ CCNxManifestHashGroup *groupA = _ccnxManifestFacadeV1_GetHashGroup(dictA, i);
+ CCNxManifestHashGroup *groupB = _ccnxManifestFacadeV1_GetHashGroup(dictB, i);
+
+ if (!ccnxManifestHashGroup_Equals(groupA, groupB)) {
+ ccnxManifestHashGroup_Release(&groupA);
+ ccnxManifestHashGroup_Release(&groupB);
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+};
+
+CCNxManifestInterface CCNxManifestFacadeV1_Interface = {
+ .description = "CCNxManifestFacadeV1_Implementation",
+ .create = &_ccnxManifestFacadeV1_Create,
+ .getName = &_ccnxManifestFacadeV1_GetName,
+ .addHashGroup = &_ccnxManifestFacadeV1_AddHashGroup,
+ .getHashGroup = &_ccnxManifestFacadeV1_GetHashGroup,
+ .getNumberOfHashGroups = &_ccnxManifestFacadeV1_GetNumberOfHashGroups,
+ .equals = &_ccnxManifestFacadeV1_Equals,
+};
diff --git a/libccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.h
new file mode 100755
index 00000000..0b5aab5a
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_ManifestFacadeV1.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * @file ccnx_ManifestFacadeV1.h
+ * @ingroup Manifest
+ * @brief A CCN Manifest facade over a CCNxTlvDictionary, using V1 schema.
+ *
+ */
+#ifndef libccnx_ccnx_ManifestFacadeV1_h
+#define libccnx_ccnx_ManifestFacadeV1_h
+
+#include <ccnx/common/internal/ccnx_ManifestInterface.h>
+
+extern CCNxManifestInterface CCNxManifestFacadeV1_Interface;
+
+#endif // libccnx_ccnx_ManifestFacadeV1_h
diff --git a/libccnx-common/ccnx/common/internal/ccnx_ManifestInterface.c b/libccnx-common/ccnx/common/internal/ccnx_ManifestInterface.c
new file mode 100755
index 00000000..581eb93c
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_ManifestInterface.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/ccnx_PayloadType.h>
+#include <ccnx/common/internal/ccnx_ManifestInterface.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+CCNxManifestInterface *
+ccnxManifestInterface_GetInterface(const CCNxTlvDictionary *dictionary)
+{
+ assertTrue(ccnxTlvDictionary_IsManifest(dictionary), "Expected a Manifest");
+
+ CCNxManifestInterface *impl = (CCNxManifestInterface *) ccnxTlvDictionary_GetMessageInterface(dictionary);
+
+ if (impl == NULL) {
+ // If we're here, we need to update the implementation pointer.
+ // Figure out what the typeImplementation should be, based on the attributes we know.
+ int schemaVersion = ccnxTlvDictionary_GetSchemaVersion(dictionary);
+
+ switch (schemaVersion) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ impl = &CCNxManifestFacadeV1_Interface;
+ break;
+ default:
+ trapUnexpectedState("Unknown SchemaVersion encountered in ccnxInterestImplementation_GetImplementation()");
+ break;
+ }
+
+ if (impl == NULL) {
+ // The cast to (CCNxTlvDictionary *) is to break the const.
+ ccnxTlvDictionary_SetMessageInterface((CCNxTlvDictionary *) dictionary, (CCNxMessageInterface *) impl);
+ }
+ }
+
+ return impl;
+}
diff --git a/libccnx-common/ccnx/common/internal/ccnx_ManifestInterface.h b/libccnx-common/ccnx/common/internal/ccnx_ManifestInterface.h
new file mode 100644
index 00000000..75855b0c
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_ManifestInterface.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * @brief A structure of functions representing a Manifest implementation.
+ *
+ * The underlying implementation should support the CCNxManifest API.
+ *
+ */
+
+#ifndef CCNx_Common_ccnx_internal_ManifestImpl_h
+#define CCNx_Common_ccnx_internal_ManifestImpl_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/ccnx_ManifestHashGroup.h>
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/common/ccnx_KeyLocator.h>
+
+#include "ccnx_TlvDictionary.h"
+
+typedef struct ccnx_manifest_interface {
+ /** A human-readable label for this implementation */
+ char *description;
+
+ /** @see ccnxManifest_Create */
+ CCNxTlvDictionary *(*create)(const CCNxName * name);
+
+ /** @see ccnxManifest_AddHashGroup */
+ void (*addHashGroup)(CCNxTlvDictionary *dict, const CCNxManifestHashGroup *group);
+
+ /** @see ccnxManifest_GetHashGroup */
+ CCNxManifestHashGroup *(*getHashGroup)(const CCNxTlvDictionary * dict, size_t index);
+
+ /** @see ccnxManifest_GetNumberOfHashGroups */
+ size_t (*getNumberOfHashGroups)(const CCNxTlvDictionary *dict);
+
+ /** @see ccnxManifest_Equals */
+ bool (*equals)(const CCNxTlvDictionary *objectA, const CCNxTlvDictionary *objectB);
+
+ /** @see ccnxManifest_GetName */
+ const CCNxName *(*getName)(const CCNxTlvDictionary * dict);
+} CCNxManifestInterface;
+
+CCNxManifestInterface *ccnxManifestInterface_GetInterface(const CCNxTlvDictionary *dictionary);
+
+/**
+ * The SchemaV1 Manifest implementaton
+ */
+extern CCNxManifestInterface CCNxManifestFacadeV1_Interface;
+
+#endif
diff --git a/libccnx-common/ccnx/common/internal/ccnx_MessageInterface.h b/libccnx-common/ccnx/common/internal/ccnx_MessageInterface.h
new file mode 100755
index 00000000..1f438348
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_MessageInterface.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#ifndef CCNx_Common_ccnx_MessageInterface_h
+#define CCNx_Common_ccnx_MessageInterface_h
+
+/**
+ * A type to represent the ContentObject/Interest/Control Interface pointer. The CCNxTlvDictionary
+ * maintains one that points to the appropriate interface implementation to reference the data
+ * contained in the CCNxTlvDictionary. For example, it might point to a CCNxContentObjectInterface,
+ * which would enable accessing the CCNxTlvDictionary as a ContentObject.
+ *
+ *
+ * @see CCNxContentObjectInterface
+ * @see CCNxInterestInterface
+ */
+typedef void CCNxMessageInterface;
+#endif
diff --git a/libccnx-common/ccnx/common/internal/ccnx_TlvDictionary.c b/libccnx-common/ccnx/common/internal/ccnx_TlvDictionary.c
new file mode 100755
index 00000000..3c768529
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_TlvDictionary.c
@@ -0,0 +1,1022 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ *
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <ccnx/common/ccnx_Name.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_JSON.h>
+
+#define DEBUG_ALLOCS 0
+
+struct ccnx_tlv_dictionary_entry;
+typedef struct ccnx_tlv_list_entry _CCNxTlvDictionaryListEntry;
+
+typedef enum {
+ CCNxTlvDictionaryType_Unknown,
+ CCNxTlvDictionaryType_Interest,
+ CCNxTlvDictionaryType_ContentObject,
+ CCNxTlvDictionaryType_Control,
+ CCNxTlvDictionaryType_InterestReturn,
+ CCNxTlvDictionaryType_Manifest
+} _CCNxTlvDictionaryType;
+
+// These form a singly linked list
+struct ccnx_tlv_list_entry {
+ _CCNxTlvDictionaryListEntry *next;
+ PARCBuffer *buffer;
+ uint16_t key;
+};
+
+#define ENTRY_UNSET ((int) 0)
+#define ENTRY_BUFFER ((int) 1)
+#define ENTRY_NAME ((int) 2)
+#define ENTRY_INTEGER ((int) 3)
+#define ENTRY_IOVEC ((int) 4)
+#define ENTRY_JSON ((int) 5)
+#define ENTRY_OBJECT ((int) 6)
+
+static struct dictionary_type_string {
+ _CCNxTlvDictionaryType type;
+ const char *string;
+} ccnxTlvDictionaryTypeStrings [] = {
+ { .type = CCNxTlvDictionaryType_Unknown, .string = "Invalid" },
+ { .type = CCNxTlvDictionaryType_Interest, .string = "Interest" },
+ { .type = CCNxTlvDictionaryType_ContentObject, .string = "Content Object" },
+ { .type = CCNxTlvDictionaryType_Control, .string = "Control" },
+ { .type = CCNxTlvDictionaryType_InterestReturn, .string = "InterestReturn" },
+ { .type = CCNxTlvDictionaryType_Manifest, .string = "Manifest" },
+ { .type = UINT32_MAX, .string = NULL },
+};
+
+static struct dictionary_entry_type_string {
+ int type;
+ const char *string;
+} ccnxTlvDictionaryEntryTypeStrings [] = {
+ { .type = ENTRY_UNSET, .string = "Unset" },
+ { .type = ENTRY_BUFFER, .string = "Buffer" },
+ { .type = ENTRY_NAME, .string = "Name" },
+ { .type = ENTRY_INTEGER, .string = "Integer" },
+ { .type = ENTRY_IOVEC, .string = "IoVec" },
+ { .type = ENTRY_JSON, .string = "JSON" },
+ { .type = ENTRY_OBJECT, .string = "Object" },
+ { .type = UINT32_MAX, .string = NULL },
+};
+
+static const char *ccnxTlvDictionaryTypeUnknown = "Unknown";
+
+static const char *
+_ccnxTlvDictionaryEntryTypeToString(int entryType)
+{
+ for (int i = 0; ccnxTlvDictionaryEntryTypeStrings[i].string != NULL; i++) {
+ if (ccnxTlvDictionaryEntryTypeStrings[i].type == entryType) {
+ return ccnxTlvDictionaryEntryTypeStrings[i].string;
+ }
+ }
+ return ccnxTlvDictionaryTypeUnknown;
+}
+
+static const char *
+_ccnxTlvDictionaryTypeToString(_CCNxTlvDictionaryType dictionaryType)
+{
+ for (int i = 0; ccnxTlvDictionaryTypeStrings[i].string != NULL; i++) {
+ if (ccnxTlvDictionaryTypeStrings[i].type == dictionaryType) {
+ return ccnxTlvDictionaryTypeStrings[i].string;
+ }
+ }
+ return ccnxTlvDictionaryTypeUnknown;
+}
+
+
+typedef struct ccnx_tlv_dictionary_entry {
+ int entryType;
+ union u_entry {
+ PARCBuffer *buffer;
+ uint64_t integer;
+ CCNxName *name;
+ CCNxCodecNetworkBufferIoVec *vec;
+ PARCJSON *json;
+ PARCObject *object;
+ } _entry;
+} _CCNxTlvDictionaryEntry;
+
+struct ccnx_tlv_dictionary {
+#define FIXED_LIST_LENGTH 8
+ // These are linked lists where we put unknown TLV types. This one static allocation should
+ // be enough for all the current packet formats.
+ _CCNxTlvDictionaryListEntry *fixedListHeads[FIXED_LIST_LENGTH];
+
+ // if we need to allocate beyond FIXED_LIST_LENGTH, put them here
+ _CCNxTlvDictionaryListEntry **extraListHeads;
+
+ size_t fastArraySize;
+ size_t listSize;
+
+ _CCNxTlvDictionaryType dictionaryType;
+ CCNxTlvDictionary_SchemaVersion schemaVersion;
+
+ // Detects changes in the dictionary that were not caused by us
+ uint32_t generation;
+
+ struct timeval creationTime;
+
+ void (*infoFreeFunction)(void **infoPtr);
+ void *info;
+
+ // A pointer to the implementation functions for the type contained by this dictionary.
+ // It's a runtime static, and is not encoded. Thus, when a dictionary is received over
+ // the wire, it will need to be initialized based on the dictionaryType and schemaVersion.
+ CCNxMessageInterface *messageInterface;
+
+ // will be allocated as part of the ccnx_tlv_dictionary
+ _CCNxTlvDictionaryEntry directArray[CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END];
+};
+
+static _CCNxTlvDictionaryListEntry *
+_ccnxTlvDictionaryListEntry_Create(uint32_t key, const PARCBuffer *buffer)
+{
+ _CCNxTlvDictionaryListEntry *entry = parcMemory_AllocateAndClear(sizeof(_CCNxTlvDictionaryListEntry));
+ assertNotNull(entry, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(_CCNxTlvDictionaryListEntry));
+ entry->key = key;
+ entry->buffer = parcBuffer_Acquire(buffer);
+
+ return entry;
+}
+
+static void
+_ccnxTlvDictionaryListEntry_Release(_CCNxTlvDictionaryListEntry **entryPtr)
+{
+ _CCNxTlvDictionaryListEntry *entry = *entryPtr;
+ parcBuffer_Release(&entry->buffer);
+ parcMemory_Deallocate((void **) &entry);
+ *entryPtr = NULL;
+}
+
+static void
+_ccnxTlvDictionaryEntry_ListRelease(_CCNxTlvDictionaryListEntry **listHeadPtr)
+{
+ _CCNxTlvDictionaryListEntry *listHead = *listHeadPtr;
+ while (listHead) {
+ _CCNxTlvDictionaryListEntry *next = listHead->next;
+ _ccnxTlvDictionaryListEntry_Release(&listHead);
+ listHead = next;
+ }
+ *listHeadPtr = NULL;
+}
+
+static void
+_ccnxTlvDictionary_FinalRelease(CCNxTlvDictionary **dictionaryPtr)
+{
+ CCNxTlvDictionary *dictionary = *dictionaryPtr;
+
+ // release any entries stored in the fast array
+ for (int i = 0; i < dictionary->fastArraySize; i++) {
+ switch (dictionary->directArray[i].entryType) {
+ case ENTRY_BUFFER:
+ parcBuffer_Release(&dictionary->directArray[i]._entry.buffer);
+ break;
+ case ENTRY_NAME:
+ ccnxName_Release(&dictionary->directArray[i]._entry.name);
+ break;
+ case ENTRY_IOVEC:
+ ccnxCodecNetworkBufferIoVec_Release(&dictionary->directArray[i]._entry.vec);
+ break;
+ case ENTRY_JSON:
+ parcJSON_Release(&dictionary->directArray[i]._entry.json);
+ break;
+ case ENTRY_OBJECT:
+ parcObject_Release(&dictionary->directArray[i]._entry.object);
+ break;
+ default:
+ // other types are direct storage
+ break;
+ }
+ }
+
+ for (int i = 0; i < FIXED_LIST_LENGTH; i++) {
+ if (dictionary->fixedListHeads[i]) {
+ _ccnxTlvDictionaryEntry_ListRelease(&dictionary->fixedListHeads[i]);
+ }
+ }
+
+ if (dictionary->extraListHeads) {
+ for (int i = FIXED_LIST_LENGTH; i < dictionary->listSize; i++) {
+ if (dictionary->extraListHeads[i - FIXED_LIST_LENGTH]) {
+ _ccnxTlvDictionaryEntry_ListRelease(&dictionary->extraListHeads[i - FIXED_LIST_LENGTH]);
+ }
+ }
+ parcMemory_Deallocate((void **) &(dictionary->extraListHeads));
+ }
+
+ if (dictionary->infoFreeFunction) {
+ dictionary->infoFreeFunction(&dictionary->info);
+ }
+
+#if DEBUG_ALLOCS
+ printf("finalize dictionary %p (final)\n", dictionary);
+#endif
+}
+
+parcObject_ExtendPARCObject(CCNxTlvDictionary, _ccnxTlvDictionary_FinalRelease,
+ NULL, NULL, ccnxTlvDictionary_Equals, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(ccnxTlvDictionary, CCNxTlvDictionary);
+
+parcObject_ImplementRelease(ccnxTlvDictionary, CCNxTlvDictionary);
+
+static void
+_ccnxTlvDictionary_GetTimeOfDay(struct timeval *outputTime)
+{
+#ifdef DEBUG
+ // if in debug mode, time messages
+ gettimeofday(outputTime, NULL);
+#else
+ *outputTime = (struct timeval) { 0, 0 };
+#endif
+}
+
+
+CCNxTlvDictionary *
+ccnxTlvDictionary_Create(size_t bufferCount, size_t listCount)
+{
+ CCNxTlvDictionary *dictionary = (CCNxTlvDictionary *) parcObject_CreateAndClearInstance(CCNxTlvDictionary);
+
+ if (dictionary != NULL) {
+ _ccnxTlvDictionary_GetTimeOfDay(&dictionary->creationTime);
+
+ dictionary->dictionaryType = CCNxTlvDictionaryType_Unknown;
+ dictionary->fastArraySize = bufferCount;
+ dictionary->listSize = listCount;
+
+ dictionary->infoFreeFunction = NULL;
+ dictionary->info = NULL;
+
+ dictionary->extraListHeads = NULL;
+ // dictionary->directArray is allocated as part of parcObject
+ }
+
+#if DEBUG_ALLOCS
+ printf("allocate dictionary %p\n", dictionary);
+#endif
+
+ return dictionary;
+}
+
+CCNxTlvDictionary *
+ccnxTlvDictionary_ShallowCopy(const CCNxTlvDictionary *source)
+{
+ size_t bufferCount = source->fastArraySize;
+ size_t listCount = source->listSize;
+ CCNxTlvDictionary *newDictionary = ccnxTlvDictionary_Create(bufferCount, listCount);
+
+ if (newDictionary != NULL) {
+ newDictionary->dictionaryType = source->dictionaryType;
+ newDictionary->schemaVersion = source->schemaVersion;
+ newDictionary->generation = source->generation;
+ newDictionary->creationTime = source->creationTime;
+ newDictionary->messageInterface = source->messageInterface;
+ newDictionary->info = source->info;
+ newDictionary->infoFreeFunction = source->infoFreeFunction;
+
+ // Update listHeads
+ for (uint32_t key = 0; key < source->listSize; ++key) {
+ size_t listSize = ccnxTlvDictionary_ListSize(source, key);
+ for (size_t i = 0; i < listSize; ++i) {
+ PARCBuffer *buffer;
+ uint32_t bKey;
+ ccnxTlvDictionary_ListGetByPosition(source, key, i, &buffer, &bKey);
+ parcBuffer_Acquire(buffer);
+ ccnxTlvDictionary_PutListBuffer(newDictionary, key, bKey, buffer);
+ parcBuffer_Release(&buffer);
+ }
+ }
+
+ // Update directArray
+ for (uint32_t key = 0; key < source->fastArraySize; ++key) {
+ switch (source->directArray[key].entryType) {
+ case ENTRY_BUFFER:
+ ccnxTlvDictionary_PutBuffer(newDictionary, key, ccnxTlvDictionary_GetBuffer(source, key));
+ break;
+ case ENTRY_NAME:
+ ccnxTlvDictionary_PutName(newDictionary, key, ccnxTlvDictionary_GetName(source, key));
+ break;
+ case ENTRY_IOVEC:
+ ccnxTlvDictionary_PutIoVec(newDictionary, key, ccnxTlvDictionary_GetIoVec(source, key));
+ break;
+ case ENTRY_JSON:
+ ccnxTlvDictionary_PutJson(newDictionary, key, ccnxTlvDictionary_GetJson(source, key));
+ break;
+ case ENTRY_INTEGER:
+ ccnxTlvDictionary_PutInteger(newDictionary, key, ccnxTlvDictionary_GetInteger(source, key));
+ break;
+ case ENTRY_OBJECT:
+ ccnxTlvDictionary_PutObject(newDictionary, key, ccnxTlvDictionary_GetObject(source, key));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return newDictionary;
+}
+
+bool
+ccnxTlvDictionary_PutBuffer(CCNxTlvDictionary *dictionary, uint32_t key, const PARCBuffer *buffer)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+
+ if (dictionary->directArray[key].entryType == ENTRY_UNSET) {
+ dictionary->directArray[key].entryType = ENTRY_BUFFER;
+ dictionary->directArray[key]._entry.buffer = parcBuffer_Acquire(buffer);
+ return true;
+ }
+ return false;
+}
+
+bool
+ccnxTlvDictionary_PutObject(CCNxTlvDictionary *dictionary, uint32_t key, const PARCObject *object)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertNotNull(object, "Parameter object must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key %ud must be less than %zu", key, dictionary->fastArraySize);
+
+ if (dictionary->directArray[key].entryType == ENTRY_UNSET) {
+ dictionary->directArray[key].entryType = ENTRY_OBJECT;
+ dictionary->directArray[key]._entry.object = parcObject_Acquire(object);
+ return true;
+ }
+ return false;
+}
+
+bool
+ccnxTlvDictionary_PutName(CCNxTlvDictionary *dictionary, uint32_t key, const CCNxName *name)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertNotNull(name, "Parameter buffer must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+
+ if (dictionary->directArray[key].entryType == ENTRY_UNSET) {
+ dictionary->directArray[key].entryType = ENTRY_NAME;
+ dictionary->directArray[key]._entry.name = ccnxName_Acquire(name);
+ return true;
+ }
+ return false;
+}
+
+bool
+ccnxTlvDictionary_PutInteger(CCNxTlvDictionary *dictionary, uint32_t key, const uint64_t value)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+
+ if (dictionary->directArray[key].entryType == ENTRY_UNSET || dictionary->directArray[key].entryType == ENTRY_INTEGER) {
+ dictionary->directArray[key].entryType = ENTRY_INTEGER;
+ dictionary->directArray[key]._entry.integer = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+ccnxTlvDictionary_PutIoVec(CCNxTlvDictionary *dictionary, uint32_t key, const CCNxCodecNetworkBufferIoVec *vec)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertNotNull(vec, "Parameter buffer must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+
+ if (dictionary->directArray[key].entryType == ENTRY_UNSET) {
+ dictionary->directArray[key].entryType = ENTRY_IOVEC;
+ dictionary->directArray[key]._entry.vec = ccnxCodecNetworkBufferIoVec_Acquire((CCNxCodecNetworkBufferIoVec *) vec);
+ return true;
+ }
+ return false;
+}
+
+bool
+ccnxTlvDictionary_PutJson(CCNxTlvDictionary *dictionary, uint32_t key, const PARCJSON *json)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertNotNull(json, "Parameter json must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+
+ if (dictionary->directArray[key].entryType == ENTRY_UNSET) {
+ dictionary->directArray[key].entryType = ENTRY_JSON;
+ dictionary->directArray[key]._entry.json = parcJSON_Acquire(json);
+ return true;
+ }
+ return false;
+}
+
+CCNxCodecNetworkBufferIoVec *
+ccnxTlvDictionary_GetIoVec(const CCNxTlvDictionary *dictionary, uint32_t key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+
+ if (dictionary->directArray[key].entryType == ENTRY_IOVEC) {
+ return dictionary->directArray[key]._entry.vec;
+ }
+ return NULL;
+}
+
+// If you need to change the list head, use this
+static _CCNxTlvDictionaryListEntry **
+_getListHeadReference(CCNxTlvDictionary *dictionary, uint32_t listKey)
+{
+ if (listKey < FIXED_LIST_LENGTH) {
+ return &dictionary->fixedListHeads[listKey];
+ } else {
+ if (dictionary->extraListHeads == NULL) {
+ dictionary->extraListHeads = parcMemory_AllocateAndClear(sizeof(_CCNxTlvDictionaryListEntry *) * (dictionary->listSize - FIXED_LIST_LENGTH));
+ }
+
+ return &dictionary->extraListHeads[listKey - FIXED_LIST_LENGTH];
+ }
+}
+
+// If not going to modify the list, use this
+static _CCNxTlvDictionaryListEntry *
+_getListHead(const CCNxTlvDictionary *dictionary, uint32_t listKey)
+{
+ _CCNxTlvDictionaryListEntry **head = _getListHeadReference((CCNxTlvDictionary *) dictionary, listKey);
+ return *head;
+}
+
+bool
+ccnxTlvDictionary_PutListBuffer(CCNxTlvDictionary *dictionary, uint32_t listKey, uint32_t key, const PARCBuffer *buffer)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertNotNull(buffer, "Parameter buffer must be non-null");
+ assertTrue(listKey < dictionary->listSize, "Parameter key must be less than %zu", dictionary->listSize);
+
+ _CCNxTlvDictionaryListEntry *entry = _ccnxTlvDictionaryListEntry_Create(key, buffer);
+
+ _CCNxTlvDictionaryListEntry **head = _getListHeadReference(dictionary, listKey);
+ if (*head) {
+ // insert new value at list head
+ entry->next = *head;
+ *head = entry;
+ } else {
+ // new value is the list head
+ *head = entry;
+ }
+ return true;
+}
+
+bool
+ccnxTlvDictionary_IsValueBuffer(const CCNxTlvDictionary *dictionary, uint32_t key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+ return (dictionary->directArray[key].entryType == ENTRY_BUFFER);
+}
+
+bool
+ccnxTlvDictionary_IsValueObject(const CCNxTlvDictionary *dictionary, uint32_t key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+ return (dictionary->directArray[key].entryType == ENTRY_OBJECT);
+}
+
+bool
+ccnxTlvDictionary_IsValueInteger(const CCNxTlvDictionary *dictionary, uint32_t key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+ return (dictionary->directArray[key].entryType == ENTRY_INTEGER);
+}
+
+bool
+ccnxTlvDictionary_IsValueName(const CCNxTlvDictionary *dictionary, uint32_t key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+ return (dictionary->directArray[key].entryType == ENTRY_NAME);
+}
+
+bool
+ccnxTlvDictionary_IsValueIoVec(const CCNxTlvDictionary *dictionary, uint32_t key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+ return (dictionary->directArray[key].entryType == ENTRY_IOVEC);
+}
+
+bool
+ccnxTlvDictionary_IsValueJson(const CCNxTlvDictionary *dictionary, uint32_t key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+ return (dictionary->directArray[key].entryType == ENTRY_JSON);
+}
+
+PARCBuffer *
+ccnxTlvDictionary_GetBuffer(const CCNxTlvDictionary *dictionary, uint32_t key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+
+ // For now return NULL for backward compatability with prior code, case 1011
+ if (dictionary->directArray[key].entryType == ENTRY_BUFFER) {
+ return dictionary->directArray[key]._entry.buffer;
+ }
+ return NULL;
+}
+
+CCNxName *
+ccnxTlvDictionary_GetName(const CCNxTlvDictionary *dictionary, uint32_t key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+
+ if (dictionary->directArray[key].entryType == ENTRY_NAME) {
+ return dictionary->directArray[key]._entry.name;
+ }
+ return NULL;
+}
+
+uint64_t
+ccnxTlvDictionary_GetInteger(const CCNxTlvDictionary *dictionary, uint32_t key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+
+ trapIllegalValueIf(dictionary->directArray[key].entryType != ENTRY_INTEGER,
+ "Key %u is of type %d",
+ key, dictionary->directArray[key].entryType)
+ {
+ ccnxTlvDictionary_Display(dictionary, 3);
+ }
+
+ return dictionary->directArray[key]._entry.integer;
+}
+
+
+PARCJSON *
+ccnxTlvDictionary_GetJson(const CCNxTlvDictionary *dictionary, uint32_t key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+
+ if (dictionary->directArray[key].entryType == ENTRY_JSON) {
+ return dictionary->directArray[key]._entry.json;
+ }
+ return NULL;
+}
+
+PARCObject *
+ccnxTlvDictionary_GetObject(const CCNxTlvDictionary *dictionary, uint32_t key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(key < dictionary->fastArraySize, "Parameter key must be less than %zu", dictionary->fastArraySize);
+
+ if (dictionary->directArray[key].entryType == ENTRY_OBJECT) {
+ return dictionary->directArray[key]._entry.object;
+ }
+
+ return NULL;
+}
+
+bool
+ccnxTlvDictionary_ListGetByPosition(const CCNxTlvDictionary *dictionary, uint32_t listKey, size_t listPosition, PARCBuffer **bufferPtr, uint32_t *keyPtr)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertNotNull(bufferPtr, "Parameter bufferPtr must be non-null");
+ assertNotNull(keyPtr, "Parameter keyPtr must be non-null");
+ assertTrue(listKey < dictionary->listSize, "Parameter key must be less than %zu", dictionary->listSize);
+
+ _CCNxTlvDictionaryListEntry *entry = _getListHead(dictionary, listKey);
+ while (entry) {
+ if (listPosition == 0) {
+ *bufferPtr = entry->buffer;
+ *keyPtr = entry->key;
+ return true;
+ }
+ entry = entry->next;
+ --listPosition;
+ }
+
+ return false;
+}
+
+
+PARCBuffer *
+ccnxTlvDictionary_ListGetByType(const CCNxTlvDictionary *dictionary, uint32_t listKey, uint32_t type)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(listKey < dictionary->listSize, "Parameter key must be less than %zu", dictionary->listSize);
+
+ PARCBuffer *buffer = NULL;
+ _CCNxTlvDictionaryListEntry *entry = _getListHead(dictionary, listKey);
+ while (entry) {
+ if (entry->key == type) {
+ buffer = entry->buffer;
+ break;
+ }
+ entry = entry->next;
+ }
+
+ return buffer;
+}
+
+
+size_t
+ccnxTlvDictionary_ListSize(const CCNxTlvDictionary *dictionary, uint32_t listKey)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertTrue(listKey < dictionary->listSize, "Parameter key must be less than %zu", dictionary->listSize);
+
+ size_t size = 0;
+ _CCNxTlvDictionaryListEntry *entry = _getListHead(dictionary, listKey);
+ while (entry) {
+ size++;
+ entry = entry->next;
+ }
+
+ return size;
+}
+
+void
+ccnxTlvDictionary_SetMessageType_Interest(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion)
+{
+ dictionary->dictionaryType = CCNxTlvDictionaryType_Interest;
+ dictionary->schemaVersion = schemaVersion;
+}
+
+void
+ccnxTlvDictionary_SetMessageType_ContentObject(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion)
+{
+ dictionary->dictionaryType = CCNxTlvDictionaryType_ContentObject;
+ dictionary->schemaVersion = schemaVersion;
+}
+
+void
+ccnxTlvDictionary_SetMessageType_Control(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion)
+{
+ dictionary->dictionaryType = CCNxTlvDictionaryType_Control;
+ dictionary->schemaVersion = schemaVersion;
+}
+
+void
+ccnxTlvDictionary_SetMessageType_InterestReturn(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion)
+{
+ dictionary->dictionaryType = CCNxTlvDictionaryType_InterestReturn;
+ dictionary->schemaVersion = schemaVersion;
+}
+
+void
+ccnxTlvDictionary_SetMessageType_Manifest(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion)
+{
+ dictionary->dictionaryType = CCNxTlvDictionaryType_Manifest;
+ dictionary->schemaVersion = schemaVersion;
+}
+
+bool
+ccnxTlvDictionary_IsInterest(const CCNxTlvDictionary *dictionary)
+{
+ return (dictionary->dictionaryType == CCNxTlvDictionaryType_Interest);
+}
+
+bool
+ccnxTlvDictionary_IsInterestReturn(const CCNxTlvDictionary *dictionary)
+{
+ return (dictionary->dictionaryType == CCNxTlvDictionaryType_InterestReturn);
+}
+
+bool
+ccnxTlvDictionary_IsContentObject(const CCNxTlvDictionary *dictionary)
+{
+ return (dictionary->dictionaryType == CCNxTlvDictionaryType_ContentObject);
+}
+
+bool
+ccnxTlvDictionary_IsControl(const CCNxTlvDictionary *dictionary)
+{
+ return (dictionary->dictionaryType == CCNxTlvDictionaryType_Control);
+}
+
+bool
+ccnxTlvDictionary_IsManifest(const CCNxTlvDictionary *dictionary)
+{
+ return (dictionary->dictionaryType == CCNxTlvDictionaryType_Manifest);
+}
+
+CCNxTlvDictionary_SchemaVersion
+ccnxTlvDictionary_GetSchemaVersion(const CCNxTlvDictionary *dictionary)
+{
+ return dictionary->schemaVersion;
+}
+
+void
+ccnxTlvDictionary_SetMessageInterface(CCNxTlvDictionary *dictionary, const CCNxMessageInterface *implementation)
+{
+ dictionary->messageInterface = (CCNxMessageInterface *) implementation;
+}
+
+CCNxMessageInterface *
+ccnxTlvDictionary_GetMessageInterface(const CCNxTlvDictionary *dictionary)
+{
+ return dictionary->messageInterface;
+}
+
+struct timeval
+ccnxTlvDictionary_GetLifetime(const CCNxTlvDictionary *dictionary)
+{
+ struct timeval now;
+ _ccnxTlvDictionary_GetTimeOfDay(&now);
+ timersub(&now, &dictionary->creationTime, &now);
+ return now;
+}
+
+static void
+_ccnxTlvDictionary_DisplayBuffer(const _CCNxTlvDictionaryEntry *entry, int index)
+{
+ printf(" Entry %3d type %8s pointer %p\n", index, _ccnxTlvDictionaryEntryTypeToString(entry->entryType), (void *) entry->_entry.buffer);
+ parcBuffer_Display(entry->_entry.buffer, 6);
+}
+
+static void
+_ccnxTlvDictionary_DisplayInteger(const _CCNxTlvDictionaryEntry *entry, int index)
+{
+ printf(" Entry %3d type %8s value 0x%" PRIX64 " (%" PRIu64 ")\n", index, _ccnxTlvDictionaryEntryTypeToString(entry->entryType), entry->_entry.integer, entry->_entry.integer);
+}
+
+static void
+_ccnxTlvDictionary_DisplayIoVec(const _CCNxTlvDictionaryEntry *entry, int index)
+{
+ printf(" Entry %3d type %8s pointer %p\n", index, _ccnxTlvDictionaryEntryTypeToString(entry->entryType), (void *) entry->_entry.vec);
+ ccnxCodecNetworkBufferIoVec_Display(entry->_entry.vec, 6);
+}
+
+static void
+_ccnxTlvDictionary_DisplayJson(const _CCNxTlvDictionaryEntry *entry, int index)
+{
+ printf(" Entry %3d type %8s pointer %p\n", index, _ccnxTlvDictionaryEntryTypeToString(entry->entryType), (void *) entry->_entry.json);
+ char *string = parcJSON_ToString(entry->_entry.json);
+ printf("%s\n", string);
+ parcMemory_Deallocate((void **) &string);
+}
+
+static void
+_ccnxTlvDictionary_DisplayName(const _CCNxTlvDictionaryEntry *entry, int index)
+{
+ printf(" Entry %3d type %8s pointer %p\n", index, _ccnxTlvDictionaryEntryTypeToString(entry->entryType), (void *) entry->_entry.name);
+ ccnxName_Display(entry->_entry.name, 6);
+}
+
+static void
+_ccnxTlvDictionary_DisplayUnknown(const _CCNxTlvDictionaryEntry *entry, int index)
+{
+ printf(" Entry %3d type %8s pointer %p\n", index, _ccnxTlvDictionaryEntryTypeToString(entry->entryType), (void *) entry->_entry.buffer);
+}
+
+static void
+_ccnxTlvDictionary_DisplayListEntry(const _CCNxTlvDictionaryListEntry *entry, int listIndex, int position)
+{
+ printf(" List %3d Position %3d key 0x%04X pointer %p\n", listIndex, position, entry->key, (void *) entry->buffer);
+ parcBuffer_Display(entry->buffer, 6);
+}
+
+void
+ccnxTlvDictionary_Display(const CCNxTlvDictionary *dictionary, int indent)
+{
+ parcDisplayIndented_PrintLine(indent, "CCNxTlvDictionary@%p fastArraySize %zu listSize %zu dictionaryType %s schemaVersion %d refcount %" PRIu64 "\n",
+ (void *) dictionary,
+ dictionary->fastArraySize,
+ dictionary->listSize,
+ _ccnxTlvDictionaryTypeToString(dictionary->dictionaryType),
+ dictionary->schemaVersion,
+ parcObject_GetReferenceCount((PARCObject *) dictionary));
+
+ parcDisplayIndented_PrintLine(indent, " createTime %0.6f generation %u Info %p InfoFreeFunc %p\n",
+ (dictionary->creationTime.tv_sec + dictionary->creationTime.tv_usec * 1E-6),
+ dictionary->generation,
+ (void *) dictionary->info,
+ dictionary->infoFreeFunction);
+
+ for (int i = 0; i < dictionary->fastArraySize; i++) {
+ if (dictionary->directArray[i].entryType != ENTRY_UNSET) {
+ switch (dictionary->directArray[i].entryType) {
+ case ENTRY_BUFFER:
+ _ccnxTlvDictionary_DisplayBuffer(&dictionary->directArray[i], i);
+ break;
+
+ case ENTRY_INTEGER:
+ _ccnxTlvDictionary_DisplayInteger(&dictionary->directArray[i], i);
+ break;
+
+ case ENTRY_IOVEC:
+ _ccnxTlvDictionary_DisplayIoVec(&dictionary->directArray[i], i);
+ break;
+
+ case ENTRY_JSON:
+ _ccnxTlvDictionary_DisplayJson(&dictionary->directArray[i], i);
+ break;
+
+ case ENTRY_NAME:
+ _ccnxTlvDictionary_DisplayName(&dictionary->directArray[i], i);
+ break;
+
+ default:
+ _ccnxTlvDictionary_DisplayUnknown(&dictionary->directArray[i], i);
+ }
+ }
+ }
+
+ for (int i = 0; i < dictionary->listSize; i++) {
+ _CCNxTlvDictionaryListEntry *entry = _getListHead(dictionary, i);
+ if (entry) {
+ int position = 0;
+ printf(" Displaying custom entry list index %3d head %p\n", i, (void *) entry);
+ while (entry) {
+ _ccnxTlvDictionary_DisplayListEntry(entry, i, position);
+ entry = entry->next;
+ }
+ }
+ }
+}
+
+static bool
+_ccnxTlvDictionaryEntry_Equals(const _CCNxTlvDictionaryEntry *a, const _CCNxTlvDictionaryEntry *b)
+{
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ bool equals = false;
+ if (a->entryType == b->entryType) {
+ switch (a->entryType) {
+ case ENTRY_UNSET:
+ equals = true;
+ break;
+
+ case ENTRY_BUFFER:
+ equals = parcBuffer_Equals(a->_entry.buffer, b->_entry.buffer);
+ break;
+
+ case ENTRY_OBJECT:
+ equals = parcObject_Equals(a->_entry.object, b->_entry.object);
+ break;
+
+ case ENTRY_INTEGER:
+ equals = (a->_entry.integer == b->_entry.integer);
+ break;
+
+ case ENTRY_IOVEC:
+ equals = ccnxCodecNetworkBufferIoVec_Equals(a->_entry.vec, b->_entry.vec);
+ break;
+
+ case ENTRY_JSON:
+ equals = parcJSON_Equals(a->_entry.json, b->_entry.json);
+ break;
+
+ case ENTRY_NAME:
+ equals = ccnxName_Equals(a->_entry.name, b->_entry.name);
+ break;
+
+ default:
+ trapIllegalValue(a->entryType, "Cannot compare due to unknown entry type: %d", a->entryType);
+ }
+ }
+ return equals;
+}
+
+static bool
+_ccnxTlvDictionaryListEntry_Equals(const _CCNxTlvDictionaryListEntry *a, const _CCNxTlvDictionaryListEntry *b)
+{
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (a->key == b->key) {
+ if (parcBuffer_Equals(a->buffer, b->buffer)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool
+_ccnxTlvDictionary_ListEquals(const _CCNxTlvDictionaryListEntry *listHeadA, const _CCNxTlvDictionaryListEntry *listHeadB)
+{
+ if (listHeadA == NULL && listHeadB == NULL) {
+ return true;
+ }
+
+ if (listHeadA == NULL || listHeadB == NULL) {
+ return false;
+ }
+
+ // walk both linked lists in parallel
+ while (listHeadA && listHeadB) {
+ if (!_ccnxTlvDictionaryListEntry_Equals(listHeadA, listHeadB)) {
+ return false;
+ }
+
+ listHeadA = listHeadA->next;
+ listHeadB = listHeadB->next;
+ }
+
+ // they must both be NULL otherwise the lists did not end at same place
+ if (listHeadA == NULL && listHeadB == NULL) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ * precondition: we know they are not null and they have the same fastarray size
+ */
+static bool
+_ccnxTlvDictionary_FastArrayEquals(const CCNxTlvDictionary *a, const CCNxTlvDictionary *b)
+{
+ bool equals = true;
+ for (int i = 0; i < a->fastArraySize && equals; i++) {
+ equals = _ccnxTlvDictionaryEntry_Equals(&a->directArray[i], &b->directArray[i]);
+ }
+ return equals;
+}
+
+/*
+ * preconditiona: we know they are not null and they have the same list size
+ */
+static bool
+_ccnxTlvDictionary_ListsEquals(const CCNxTlvDictionary *a, const CCNxTlvDictionary *b)
+{
+ bool equals = true;
+ for (int i = 0; i < a->listSize && equals; i++) {
+ _CCNxTlvDictionaryListEntry *entry_a = _getListHead(a, i);
+ _CCNxTlvDictionaryListEntry *entry_b = _getListHead(b, i);
+ equals = _ccnxTlvDictionary_ListEquals(entry_a, entry_b);
+ }
+ return equals;
+}
+
+bool
+ccnxTlvDictionary_Equals(const CCNxTlvDictionary *a, const CCNxTlvDictionary *b)
+{
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ // They are both non-null
+ bool equals = false;
+ if (a->fastArraySize == b->fastArraySize) {
+ if (a->listSize == b->listSize) {
+ if (a->dictionaryType == b->dictionaryType) {
+ if (a->schemaVersion == b->schemaVersion) {
+ if (_ccnxTlvDictionary_FastArrayEquals(a, b)) {
+ if (_ccnxTlvDictionary_ListsEquals(a, b)) {
+ equals = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return equals;
+}
diff --git a/libccnx-common/ccnx/common/internal/ccnx_TlvDictionary.h b/libccnx-common/ccnx/common/internal/ccnx_TlvDictionary.h
new file mode 100755
index 00000000..bae0ec8b
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_TlvDictionary.h
@@ -0,0 +1,1127 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_TlvDictionary.h
+ * @brief Stores pointers to PARCBuffers indexed by keys
+ *
+ * A message dictionary stores each field of a message in an array entry. The user of the dictionary needs to
+ * have a schema so it knows which array entry is which field.
+ *
+ * A message dictionary carries two distinguished fields that are not part of the array. The MessageType is
+ * Interest, ContentObject, or Control. The SchemaVersion is 0 or 1. These fields are independent of
+ * anything that is in the dictionary.
+ *
+ * The message dictionary creates two arrays. The first array is an array of PARCBuffer. The second array
+ * is a list of (type, PARCBuffer). This structure is designed such that well-known TLV keys
+ * are stored in the first array under well-known indicies.
+ *
+ * unknown TLV keys are stored in the second array, where each list corresponds to a TLV container.
+ * For example, an unknown TLV type found under the Content Object Metadata container would
+ * go in a list corresponding to the Metadata container and they be added to the list with the
+ * pair (type, PARCBuffer), where 'type' is the unknown TLV type.
+ *
+ */
+
+#ifndef libccnx_ccnx_TlvDictionary_h
+#define libccnx_ccnx_TlvDictionary_h
+
+#include <stdbool.h>
+#include <sys/time.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_JSON.h>
+
+#include <ccnx/common/internal/ccnx_MessageInterface.h>
+
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+
+
+struct ccnx_tlv_dictionary;
+typedef struct ccnx_tlv_dictionary CCNxTlvDictionary;
+
+typedef enum {
+ CCNxTlvDictionary_SchemaVersion_V0 = 0,
+ CCNxTlvDictionary_SchemaVersion_V1 = 1,
+} CCNxTlvDictionary_SchemaVersion;
+
+
+/**
+ * Creates a new TLV dictionary with the given size
+ *
+ * There will be 'bufferCount' array elements of type Buffer and
+ * 'listCount' elements of type List. Each array is indexed from 0.
+ *
+ * @param [in] bufferCount The number of Buffer elements to allocate within the dictionary.
+ * @param [in] listCount The number of List elements to allocate within the dictionary.
+ *
+ * @return NULL A new CCNxTlvDictionary object could not be allocated.
+ * @return CCNxTlvDictionary A new CCNxTlvDictionary instance with bufferCount Buffer and listCount List elements.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_PutBuffer(dict, 3, nameBuffer);
+ * rtatlvDictionary_PutListBuffer(dict, 2, unknownType, unknownBuffer);
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxTlvDictionary_Create(size_t bufferCount, size_t listCount);
+
+/**
+ * Acquire a handle to the CCNxTlvDictionary instance.
+ *
+ * Note that new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the reference by invoking `ccnxTlvDictionary_Release()`.
+ *
+ * @param [in] dictionary A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Acquire(instance);
+ *
+ * ccnxTlvDictionary_Release(&dict);
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxTlvDictionary_Acquire(const CCNxTlvDictionary *dictionary);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in] dictionaryPtr A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Acquire(instance);
+ *
+ * ccnxTlvDictionary_Release(&dict);
+ * }
+ * @endcode
+ */
+void ccnxTlvDictionary_Release(CCNxTlvDictionary **dictionaryPtr);
+
+/**
+ * Adds a buffer to a dictionary entry
+ *
+ * Stores a reference count to the buffer
+ *
+ * @param [in] dictionary An CCNxTlvDictionary instance to which the Buffer entry will be added.
+ * @param [in] key The integer key that is to be associated with the new Buffer entry.
+ * @param [in] buffer The Buffer entry value to be inserted into the dictionary.
+ *
+ * @return true Key was not previously set
+ * @return false Key already has a buffer assigned to it
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * PARCBuffer *buffer = parcBuffer_Allocate(1);
+ * ccnxTlvDictionary_PutBuffer(dict, 1, buffer);
+ * // use the dictionary as needed
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_PutBuffer(CCNxTlvDictionary *dictionary, uint32_t key, const PARCBuffer *buffer);
+
+/**
+ * Determine if the value associated with the specified key is a Buffer.
+ *
+ * The key must be within the interval [0, bufferCount] for the dictionary.
+ *
+ * @param [in] dictionary The dictionary instance which will be examined.
+ * @param [in] key The key to use when indexing the dictionary.
+ *
+ * @return true The value associated with the key is of type Buffer.
+ * @return false The value associated with the key is -not- of type Buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * PARCBuffer *buffer = parcBuffer_Allocate(1);
+ * ccnxTlvDictionary_PutBuffer(dict, 1, buffer);
+ * bool truthy = ccnxTlvDictionary_IsValueBuffer(dict, 1);
+ * // truthy will be true
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_IsValueBuffer(const CCNxTlvDictionary *dictionary, uint32_t key);
+
+// caw TODO
+bool ccnxTlvDictionary_IsValueObject(const CCNxTlvDictionary *dictionary, uint32_t key);
+
+/**
+ * Retrieves an entry from the dictionary from the specified key.
+ *
+ * @param [in] dictionary The dictionary instance which will be examined.
+ * @param [in] key The key to use when indexing the dictionary.
+ *
+ * @return NULL if key not found
+ * @return non-null The desired key
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * PARCBuffer *buffer = parcBuffer_Allocate(1);
+ * ccnxTlvDictionary_PutBuffer(dict, 1, buffer);
+ * PARCBuffer *copy = ccnxTlvDictionary_GetBuffer(dict, 1);
+ * // copy will be equal to the buffer instance
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxTlvDictionary_GetBuffer(const CCNxTlvDictionary *dictionary, uint32_t key);
+
+/**
+ * Put a new integer value in the dictionary, overwriting the old value if the key is
+ * already present.
+ *
+ * You can put an integer value many times, its OK to overwrite.
+ * They key must be UNSET or INTEGER, you cannot overwrite a different type
+ * The integer will be encoded as per the schema, it will not necessarily be an 8-byte field.
+ *
+ * @param [in] dictionary The dictionary instance to be modified
+ * @param [in] key The key used when indexing the dictionary
+ * @param [in] value The new value to insert into the dictionary assoicated with the above key
+ *
+ * @return true If the put/update was successful.
+ * @return false Otherwise (e.g., not UNSET/INTEGER type)
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * bool success = ccnxTlvDictionary_PutInteger(dict, 2, 1337);
+ * // success will be true since key 2 was UNSET
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_PutInteger(CCNxTlvDictionary *dictionary, uint32_t key, const uint64_t value);
+
+/**
+ * Determine if the value associated with the specified key is an Integer.
+ *
+ * The key must be within the interval [0, bufferCount] for the dictionary.
+ *
+ * @param [in] dictionary The dictionary instance which will be examined.
+ * @param [in] key The key to use when indexing the dictionary.
+ *
+ * @return true The value associated with the key is of type INTEGER.
+ * @return false The value associated with the key is -not- of type INTEGER.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_PutInteger(dict, 2, 1337);
+ * bool truthy = ccnxTlvDictionary_IsValueInteger(dict, 2);
+ * // truthy will be true
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_IsValueInteger(const CCNxTlvDictionary *dictionary, uint32_t key);
+
+/**
+ * Returns an integer value stored in a key
+ *
+ * Will trapIllegalValue if the given key is not of type Integer. You should use
+ * ccnxTlvDictionary_IsValueInteger before calling. An unset key is not of type Integer.
+ *
+ * @param [in] dictionary The dictionary to check
+ * @param [in] key The key to retrieve
+ *
+ * @return number The value stored under the key
+ *
+ * Example:
+ * @code
+ * static uint32_t
+ * _fetchUint32(const CCNxTlvDictionary *interestDictionary, uint32_t key, uint32_t defaultValue)
+ * {
+ * if (ccnxTlvDictionary_IsValueInteger(interestDictionary, key)) {
+ * return (uint32_t) ccnxTlvDictionary_GetInteger(interestDictionary, key);
+ * }
+ * return defaultValue;
+ * }
+ * @endcode
+ */
+uint64_t ccnxTlvDictionary_GetInteger(const CCNxTlvDictionary *dictionary, uint32_t key);
+
+/**
+ * Put a new CCNxName into the `CCNxTlvDictionary` instance.
+ *
+ * You can only set a Name field once. The key must be UNSET.
+ *
+ * @param [in] dictionary The dictionary instance to be modified
+ * @param [in] key The key used when indexing the dictionary
+ * @param [in] name The new CCNxName value to insert into the dictionary assoicated with the above key
+ *
+ * @return true If the put/update was successful.
+ * @return false Otherwise (e.g., not UNSET type)
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ * bool success = ccnxTlvDictionary_PutName(dict, 2, name);
+ * // success will be true since key 2 was UNSET
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_PutName(CCNxTlvDictionary *dictionary, uint32_t key, const CCNxName *name);
+
+/**
+ * Determine if the value associated with the specified key is a CCNxName.
+ *
+ * The key must be within the interval [0, bufferCount] for the dictionary.
+ *
+ * @param [in] dictionary The dictionary instance which will be examined.
+ * @param [in] key The key to use when indexing the dictionary.
+ *
+ * @return true The value associated with the key is of type NAME.
+ * @return false The value associated with the key is -not- of type NAME.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ * ccnxTlvDictionary_PutName(dict, 2, name);
+ * bool truthy = ccnxTlvDictionary_IsValueName(dict, 2);
+ * // truthy will be true since a name was inserted with key=2
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_IsValueName(const CCNxTlvDictionary *dictionary, uint32_t key);
+
+/**
+ * Retrieve the CCNxName instance associated with the specified key.
+ *
+ * The key must be within the interval [0, bufferCount] for the dictionary.
+ * The entry is expected to be of type NAME, and will return NULL if not.
+ *
+ * @param [in] dictionary The dictionary instance which will be queried.
+ * @param [in] key The key to use when indexing the dictionary.
+ *
+ * @return NULL The entry associated with the key is not of type NAME.
+ * @return CCNxName A CCNxName instance associated with the specified key.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ * ccnxTlvDictionary_PutName(dict, 2, name);
+ * CCNxName *copy = ccnxTlvDictionary_GetName(dict, 2);
+ * // do something with copy
+ * }
+ * @endcode
+ */
+CCNxName *ccnxTlvDictionary_GetName(const CCNxTlvDictionary *dictionary, uint32_t key);
+
+/**
+ * Insert a `CCNxCodecNetworkBufferIoVec` instance into the dictionary.
+ *
+ * Stores a scatter/gather network buffer. Could be either the wire format we recieve
+ * or the wire format we're about to send. The resulting entry type will be IOVEC.
+ *
+ * @param [in] dictionary The dictionary instance to be modified
+ * @param [in] key The key used when indexing the dictionary
+ * @param [in] vec The new CCNxCodecNetworkBufferIoVec value to insert into the dictionary assoicated with the above key
+ *
+ * @return true If the put/update was successful.
+ * @return false Otherwise (e.g., not UNSET type)
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * CCNxCodecNetworkBuffer *buffer = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(buffer);
+ * bool success = ccnxTlvDictionary_PutName(dict, 2, iovec);
+ * // success will be true since key 2 was UNSET
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_PutIoVec(CCNxTlvDictionary *dictionary, uint32_t key, const CCNxCodecNetworkBufferIoVec *vec);
+
+/**
+ * Determine if the value associated with the specified key is a CCNxCodecNetworkBufferIoVec.
+ *
+ * @param [in] dictionary The dictionary instance to be examined
+ * @param [in] key The key used when indexing the dictionary
+ *
+ * @return true The TLV dictionary has the given key and it is of type IOVEC
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * CCNxCodecNetworkBuffer *buffer = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(buffer);
+ * ccnxTlvDictionary_PutName(dict, 2, iovec);
+ * bool truthy = ccnxTlvDictionary_IsValueIoVec(dict, 2);
+ * // truthy will be true since key 2 was IOVEC and previously inserted
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_IsValueIoVec(const CCNxTlvDictionary *dictionary, uint32_t key);
+
+/**
+ * Retrieve the CCNxCodecNetworkBufferIoVec instance associated with the specified key.
+ *
+ * The key must be within the interval [0, bufferCount] for the dictionary.
+ * The entry is expected to be of type IOVEC, and will return NULL if not.
+ *
+ * @param [in] dictionary The dictionary instance which will be queried.
+ * @param [in] key The key to use when indexing the dictionary.
+ *
+ * @return NULL The entry associated with the key is not of type IOVEC.
+ * @return CCNxCodecNetworkBufferIoVec A CCNxCodecNetworkBufferIoVec instance associated with the specified key.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * CCNxCodecNetworkBuffer *buffer = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ * CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(buffer);
+ * ccnxTlvDictionary_PutName(dict, 2, iovec);
+ * CCNxCodecNetworkBufferIoVec *copy = ccnxTlvDictionary_GetIoVec(dict, 2);
+ * // do something with copy
+ * }
+ * @endcode
+ */
+CCNxCodecNetworkBufferIoVec *ccnxTlvDictionary_GetIoVec(const CCNxTlvDictionary *dictionary, uint32_t key);
+
+/**
+ * Insert a new List item into the dictionary.
+ *
+ * The key must be within the interval [0, bufferCount] for the dictionary.
+ * You can only set a Buffer field once. The key must be UNSET.
+ *
+ * @param [in] dictionary The dictionary instance to be modified
+ * @param [in] listKey The list key used when indexing the dictionary lists
+ * @param [in] key The key type of the element being inserted into the list
+ * @param [in] buffer The new PARCBuffer value to insert into the dictionary list indexed by the listKey
+ *
+ * @return true If the put/update was successful.
+ * @return false Otherwise (e.g., not UNSET type)
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * PARCBuffer *buffer = parcBuffer_Allocate(1);
+ * bool success = ccnxTlvDictionary_PutListBuffer(dict, 1, 1, buffer);
+ * // success will be true since list key 1 was UNSET, and the new item will have key type 1
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_PutListBuffer(CCNxTlvDictionary *dictionary, uint32_t listKey, uint32_t key, const PARCBuffer *buffer);
+
+/**
+ * Insert a new `PARCJSON` instance into the dictionary.
+ *
+ * The caller may destroy its reference to JSON since the type is deep-copied internally.
+ * The key must be within the dictionary, and the entry must be UNSET.
+ *
+ * @param [in] dictionary The dictionary instance to be modified
+ * @param [in] key The key used when indexing the dictionary
+ * @param [in] json The new PARCJSON value to insert into the dictionary associated with the above key
+ *
+ * @return true If the put/update was successful.
+ * @return false Otherwise (e.g., not UNSET type)
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * PARCJSON *json = ccnxJson_CreateNumber(1);
+ * bool success = ccnxTlvDictionary_PutJson(dict, 1, json);
+ * // success will be true since the key was UNSET
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_PutJson(CCNxTlvDictionary *dictionary, uint32_t key, const PARCJSON *json);
+
+/**
+ * Determine if the value associated with the specified key is a `PARCJSON` instance.
+ *
+ * @param [in] dictionary The dictionary instance to be examined
+ * @param [in] key The key used when indexing the dictionary
+ *
+ * @return true The TLV dictionary has the given key and it is of type JSON
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * PARCJSON *json = ccnxJson_CreateNumber(1);
+ * ccnxTlvDictionary_PutJson(dict, 1, json);
+ * bool truthy = ccnxTlvDictionary_IsValueJson(dict, 1);
+ * // truthy will be true since the JSON object was previously inserted
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_IsValueJson(const CCNxTlvDictionary *dictionary, uint32_t key);
+
+/**
+ * Retrieve the `PARCJSON` instance associated with the specified key.
+ *
+ * The key must be within the interval [0, bufferCount] for the dictionary.
+ * The entry is expected to be of type JSON, and will return NULL if not.
+ *
+ * @param [in] dictionary The dictionary instance which will be queried.
+ * @param [in] key The key to use when indexing the dictionary.
+ *
+ * @return NULL The entry associated with the key is not of type JSON.
+ * @return PARCJSON A PARCJSON instance associated with the specified key.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * PARCJSON *json = ccnxJson_CreateNumber(1);
+ * ccnxTlvDictionary_PutJson(dict, 1, json);
+ * PARCJSON *copy = ccnxTlvDictionary_GetJson(dict, 1);
+ * // do something with copy
+ * }
+ * @endcode
+ */
+PARCJSON *ccnxTlvDictionary_GetJson(const CCNxTlvDictionary *dictionary, uint32_t key);
+
+/**
+ * Insert a new `PARCJSON` instance into the dictionary.
+ *
+ * The caller may destroy its reference to PARCObject since the type is deep-copied internally.
+ * The key must be within the dictionary, and the entry must be UNSET.
+ *
+ * @param [in] dictionary The dictionary instance to be modified
+ * @param [in] key The key used when indexing the dictionary
+ * @param [in] json The new PARCObject value to insert into the dictionary associated with the above key
+ *
+ * @return true If the put/update was successful.
+ * @return false Otherwise (e.g., not UNSET type)
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * PARCObject *object = ccnxName_CreateFromCString("ccnx/test");
+ * bool success = ccnxTlvDictionary_PutObject(dict, 1, object);
+ * // success will be true since the key was UNSET
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_PutObject(CCNxTlvDictionary *dictionary, uint32_t key, const PARCObject *json);
+
+/**
+ * Determine if the value associated with the specified key is a `PARCObject` instance.
+ *
+ * @param [in] dictionary The dictionary instance to be examined
+ * @param [in] key The key used when indexing the dictionary
+ *
+ * @return true The TLV dictionary has the given key and it is of type PARCObject
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * PARCObject *object = ccnxName_CreateFromCString("ccnx/test");
+ * ccnxTlvDictionary_PutObject(dict, 1, object);
+ * bool truthy = ccnxTlvDictionary_IsValueObject(dict, 1);
+ * // truthy will be true since the PARCObject was previously inserted
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_IsValueObject(const CCNxTlvDictionary *dictionary, uint32_t key);
+
+/**
+ * Retrieve the `PARCObject` instance associated with the specified key.
+ *
+ * The key must be within the interval [0, bufferCount] for the dictionary.
+ * The entry is expected to be of type PARCObject, and will return NULL if not.
+ *
+ * @param [in] dictionary The dictionary instance which will be queried.
+ * @param [in] key The key to use when indexing the dictionary.
+ *
+ * @return NULL The entry associated with the key is not of type PARCObject.
+ * @return PARCObject A PARCObject instance associated with the specified key.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * PARCObject *object = ccnxName_CreateFromCString("ccnx/test");
+ * ccnxTlvDictionary_PutObject(dict, 1, object);
+ * PARCObject *copy = ccnxTlvDictionary_GetObject(dict, 1);
+ * // do something with copy
+ * }
+ * @endcode
+ */
+PARCObject *ccnxTlvDictionary_GetObject(const CCNxTlvDictionary *dictionary, uint32_t key);
+
+/**
+ * Fetches a buffer from the ordinal position 'listItem' from the list key 'key'
+ *
+ * The entry 'key' must be type list.
+ *
+ * @param [in] dictionary The dictionary instance being examined
+ * @param [in] listKey The key used to identify the list to be searched
+ * @param [in] listPosition The index within the target list of the dictionary
+ * @param [out] bufferPtr If position is found, the buffer at that position
+ * @param [out] keyPtr If position is found, the key of the buffer
+ *
+ * @return true position found
+ * @return false position not found
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * PARCBuffer *buffer = parcBuffer_Allocate(1);
+ * ccnxTlvDictionary_PutListBuffer(dict, 1, 1, buffer);
+ * PARCBuffer *copy = NULL;
+ * uint32_t key = 0;
+ * ccnxTlvDictionary_ListGetByPosition(dict, 1, 0, &copy, &key);
+ * // use the copy and key as necessary
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_ListGetByPosition(const CCNxTlvDictionary *dictionary, uint32_t listKey, size_t listPosition, PARCBuffer **bufferPtr, uint32_t *keyPtr);
+
+/**
+ * Returns the first buffer in the list identified by 'listkey' with the buffer type 'type'
+ *
+ * @param [in] dictionary The dictionary instance being examined
+ * @param [in] listKey The key used to index into the dictionary lists
+ * @param [in] type The type of element used to search within the dictionary list
+ *
+ * @return PARCBuffer* Pointer to the first PARCBuffer instance whose type matches the type argument in the target list
+ * @return NULL If no element in the target list has the specified type.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * PARCBuffer *buffer = parcBuffer_Allocate(1);
+ * ccnxTlvDictionary_PutListBuffer(dict, 1, 1, buffer);
+ * PARCBuffer *copy = ccnxTlvDictionary_ListGetByType(dict, 1, 1);
+ * // copy and buffer will have equal PARCBuffer values
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxTlvDictionary_ListGetByType(const CCNxTlvDictionary *dictionary, uint32_t listKey, uint32_t type);
+
+/**
+ * Retrieve the number of elements in the list identified by 'key'
+ *
+ * The dictionary entry 'key' must be of type list.
+ *
+ * @param [in] dictionary The dictionary instance to be examined
+ * @param [in] listKey The key used to index into the list whose size will be checked
+ *
+ * @return The size of the list associated with the given list key
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * PARCBuffer *buffer = parcBuffer_Allocate(1);
+ * ccnxTlvDictionary_PutListBuffer(dict, 1, 1, buffer);
+ * size_t listSize = ccnxTlvDictionary_ListSize(dictionary, 1);
+ * // listSize will be 1
+ * }
+ * @endcode
+ */
+size_t ccnxTlvDictionary_ListSize(const CCNxTlvDictionary *dictionary, uint32_t listKey);
+
+/**
+ * Set the type of message which this dictionary stores/represents to be an Interest.
+ *
+ * @param [in] dictionary The dictionary instance whose type is to be modified
+ * @param [in] schemaVersion The schema version which is used by the dictionary for message encoding.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_SetMessageType_Interest(dict, CCNxTlvDictionary_SchemaVersion_V0);
+ * // use the dictionary
+ * }
+ * @endcode
+ */
+void ccnxTlvDictionary_SetMessageType_Interest(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion);
+
+/**
+ * Set the type of message which this dictionary stores/represents to be a ContentObject.
+ *
+ * @param [in] dictionary The dictionary instance whose type is to be modified
+ * @param [in] schemaVersion The schema version which is used by the dictionary for message encoding.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_SetMessageType_ContentObject(dict, CCNxTlvDictionary_SchemaVersion_V1);
+ * // use the dictionary
+ * }
+ * @endcode
+ */
+void ccnxTlvDictionary_SetMessageType_ContentObject(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion);
+
+/**
+ * Set the type of message which this dictionary stores/represents to be a Control (message).
+ *
+ * @param [in] dictionary The dictionary instance whose type is to be modified
+ * @param [in] schemaVersion The schema version which is used by the dictionary for message encoding.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_SetMessageType_Control(dict, CCNxTlvDictionary_SchemaVersion_V1);
+ * // use the dictionary
+ * }
+ * @endcode
+ */
+void ccnxTlvDictionary_SetMessageType_Control(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion);
+
+/**
+ * Set the type of message which this dictionary stores/represents to be a Manifest (message).
+ *
+ * @param [in] dictionary The dictionary instance whose type is to be modified.
+ * @param [in] schemaVersion The schema version which is used by the dictionary for message encoding.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_SetMessageType_Manifest(dict, CCNxTlvDictionary_SchemaVersion_V1);
+ * // use the dictionary
+ * }
+ * @endcode
+ */
+void ccnxTlvDictionary_SetMessageType_Manifest(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion);
+
+/**
+ * Set the type of message which this dictionary stores/represents to be an InterestReturn.
+ *
+ * @param [in] dictionary The dictionary instance whose type is to be modified
+ * @param [in] schemaVersion The schema version which is used by the dictionary for message encoding.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_SetMessageType_InterestReturn(dict, CCNxTlvDictionary_SchemaVersion_V0);
+ * // use the dictionary
+ * }
+ * @endcode
+ */
+void ccnxTlvDictionary_SetMessageType_InterestReturn(CCNxTlvDictionary *dictionary, CCNxTlvDictionary_SchemaVersion schemaVersion);
+
+
+/**
+ * Retrieve the schema version `CCNxTlvDictionary_SchemaVersion` used to encode the contents of the dictionary.
+ *
+ * Currently, only two schema versions are supported: CCNxTlvDictionary_SchemaVersion_V0 and CCNxTlvDictionary_SchemaVersion_V1
+ *
+ * @param [in] dictionary The dictionary instance being examined
+ *
+ * @return The `CCNxTlvDictionary_SchemaVersion` version used for encoding.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_SetMessageType_Interest(dict, CCNxTlvDictionary_SchemaVersion_V0);
+ * CCNxTlvDictionary_SchemaVersion ver = ccnxTlvDictionary_GetSchemaVersion(dict);
+ * // ver will be equal to CCNxTlvDictionary_SchemaVersion_V0
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary_SchemaVersion ccnxTlvDictionary_GetSchemaVersion(const CCNxTlvDictionary *dictionary);
+
+/**
+ * Determine if the specified dictionary represents an Interest message.
+ *
+ * @param [in] dictionary The dictionary instance being examined.
+ *
+ * @return true The dictionary represents an Interest message.
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_SetMessageType_Interest(dict, CCNxTlvDictionary_SchemaVersion_V0);
+ * bool isInterest = ccnxTlvDictionary_IsInterest(dict);
+ * // isInterest will be true
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_IsInterest(const CCNxTlvDictionary *dictionary);
+
+/**
+ * Determine if the specified dictionary represents an InterestReturn message.
+ *
+ * @param [in] dictionary The dictionary instance being examined.
+ *
+ * @return true The dictionary represents an InterestReturn message.
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_SetMessageType_InterestReturn(dict, CCNxTlvDictionary_SchemaVersion_V1);
+ * bool isInterestReturn = ccnxTlvDictionary_IsInterestReturn(dict);
+ * // isInterest will be true
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_IsInterestReturn(const CCNxTlvDictionary *dictionary);
+
+/**
+ * Determine if the specified dictionary represents a ContentObject message.
+ *
+ * @param [in] dictionary The dictionary instance being examined.
+ *
+ * @return true The dictionary represents a ContentObject message.
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_SetMessageType_ContentObject(dict, CCNxTlvDictionary_SchemaVersion_V0);
+ * bool isContentObject = ccnxTlvDictionary_IsContentObject(dict);
+ * // isContentObject will be true
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_IsContentObject(const CCNxTlvDictionary *dictionary);
+
+/**
+ * Determine if the specified dictionary represents a Control message.
+ *
+ * @param [in] dictionary The dictionary instance being examined.
+ *
+ * @return true The dictionary represents a Control message.
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_SetMessageType_Control(dict, CCNxTlvDictionary_SchemaVersion_V0);
+ * bool isControl = ccnxTlvDictionary_IsControl(dict);
+ * // isControl will be true
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_IsControl(const CCNxTlvDictionary *dictionary);
+
+/**
+ * Determine if the specified dictionary represents a Manifest message.
+ *
+ * @param [in] dictionary The dictionary instance being examined.
+ *
+ * @return true The dictionary represents a Manifest message.
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_SetMessageType_Manifest(dict, CCNxTlvDictionary_SchemaVersion_V1);
+ * bool isManifest = ccnxTlvDictionary_IsManifest(dict);
+ * // isManifest will be true
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_IsManifest(const CCNxTlvDictionary *dictionary);
+
+/**
+ * If in DEBUG mode, returns how long the message has been in the system
+ *
+ * If not in DEBUG mode, will always be {.tv_sec = 0, .tv_usec = 0}. The time is based
+ * on gettimeofday().
+ *
+ * Measured since the time when the dictionary was created
+ *
+ * @param [in] dictionary The dictionary instance whose lifetime is being queried
+ *
+ * @return struct timeval The lifetime of the dictionary message.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * // do some things ...
+ * struct timeval = ccnxTlvDictionary_GetLifetime(dict);
+ * // use the time as needed
+ * }
+ * @endcode
+ */
+struct timeval ccnxTlvDictionary_GetLifetime(const CCNxTlvDictionary *dictionary);
+
+/**
+ * Display the dictionary and its contents
+ *
+ * The contents of the dictionary are printed to stdout. This is often useful
+ * for verbose debugging purposes.
+ *
+ * @param [in] indent The number of tabs to indent all lines printed on stdout
+ * @param [in] dictionary The dictionary instance whose contents will be printed to stdout
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_Display(dict, 0);
+ * }
+ * @endcode
+ */
+void ccnxTlvDictionary_Display(const CCNxTlvDictionary *dictionary, int indent);
+
+/**
+ * Determine if two CCNxTlvDictionary instances are equal.
+ *
+ * Two CCNxTlvDictionary instances are equal if, and only if, they contain the same number
+ * of keys, the keys are equal, and each key points to the same value.
+ *
+ * The following equivalence relations on non-null `CCNxTlvDictionary` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `ccnxTlvDictionary_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `ccnxTlvDictionary_Equals(x, y)` must return true if and only if
+ * `ccnxTlvDictionary_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxTlvDictionary_Equals(x, y)` returns true and
+ * `ccnxTlvDictionary_Equals(y, z)` returns true,
+ * then `ccnxTlvDictionary_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `ccnxTlvDictionary_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxTlvDictionary_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `CCNxTlvDictionary` instance.
+ * @param b A pointer to a `CCNxTlvDictionary` instance.
+ *
+ * NULL == NULL, non-NULL != NULL, otherwise the dictionaries need to be the same
+ * type, schema, and all fields must compare for equality.
+ *
+ * Equals does not include the CreationTime (lifetime) or the SetInfo() value.
+ *
+ * @return true Dictionaries are equal
+ * @return false Dictionaries differ in some way
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * CCNxTlvDictionary *dict1 = ccnxTlvDictionary_Create(5, 3);
+ * CCNxTlvDictionary *dict2 = ccnxTlvDictionary_Create(5, 3);
+ * if (ccnxTlvDictionary_Equals(dict1, dict2)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool ccnxTlvDictionary_Equals(const CCNxTlvDictionary *a, const CCNxTlvDictionary *b);
+
+/**
+ * Allocates a new instance of the specified CCNxTlvDictionary that is
+ * a "Shallow" copy of the original. The new instance contains the
+ * same contents as the original CCNxTlvDictionary but an Acquire()
+ * operation is used where possible to form a new link to the original
+ * contained content (a Copy() operation is used otherwise). Note that
+ * this means that modifying the content of the copy will, in most
+ * cases, modify the content of the original. In any case, the
+ * contents are protected from premature deallocation.
+ *
+ * @param [in] source The dictionary to copy
+ *
+ * @return CCNxTlvDictionary A pointer to a copy of the source dictionary
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * CCNxTlvDictionary *source = ccnxTlvDictionary_Create(5, 3);
+ * PARCBuffer *buffer = parcBuffer_Allocate(1);
+ * ccnxTlvDictionary_PutListBuffer(source, 1, 1, buffer);
+ * ...
+ * CCNxTlvDictionary *copy = ccnxTlvDictionary_ShallowCopy(source);
+ * PARCBuffer *buffcopy;
+ * uint32_t key = 0;
+ * ccnxTlvDictionary_ListGetByPosition(copy, 1, 0, &buffcopy, &key);
+ * ...
+ * assertTrue(ccnxTlvDictionary_Equals(source, copy), "Error: not a copy");
+ * assertTrue(buffcopy == buffer, "Error: not a shallow copy");
+ * }
+ * @endcode
+ */
+CCNxTlvDictionary *ccnxTlvDictionary_ShallowCopy(const CCNxTlvDictionary *source);
+
+/**
+ * Set the pointer to the implementation used to create the message type represented by this
+ * CCNxTlvDictionary. For example, if the CCNxTlvDictionary represents a V1 ContentObject,
+ * the implementation pointer should be set to &CCNxContentObjectFacadeV1_Implementation.
+ * The type can be inferred from the dictionary's schemaVersion and messageType.
+ *
+ * Consumers of this CCNxTlvDictionary should use the implementation pointer to access
+ * fields in the dictionary. Examples of implementations would be those that define
+ * {@link CCNxContentObjectInterface} or {@link CCNxInterestInterface}, such as
+ * {@link CCNxContentObjectFacadeV1_Implementation} or {CCNxInterestFacadeV1_Implementation}.
+ *
+ * @param [in] dictionary The dictionary instance on which to set the implementation pointer.
+ * @param [in] implementation The address of the implementation to be used to access this dictionary.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_SetMessageInterface(&CCNxContentObjectFacadeV1_Implementation);
+ * }
+ * @endcode
+ * @see `ccnxTlvDictionary_GetMessageTypeInterface`
+ */
+void ccnxTlvDictionary_SetMessageInterface(CCNxTlvDictionary *dictionary, const CCNxMessageInterface *implementation);
+
+/**
+ * Return the address of the implementation used to access fields in the the message represented by this
+ * CCNxTlvDictionary instance. The implementation pointer would typically be
+ * {@link CCNxContentObjectFacadeV1_Implementation} or {@link CCNxContentObjectFacadeV1_Implementation}.
+ * If it is not set, it can be inferred from the messageType and the schemaVersion.
+ *
+ * @param [in] dictionary The dictionary instance from which to retrieve the implementation pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(5, 3);
+ * ccnxTlvDictionary_SetMessageTypeInterface(&CCNxContentObjectFacadeV1_Implementation);
+ * CCNxContentObjectInterface *impl = ccnxTlvDictionary_GetMessageTypeInterface(dict);
+ * }
+ * @endcode
+ * @see `ccnxTlvDictionary_SetMessageTypeInterface`
+ * @see `ccnxContentObjectInterface_GetInterface`
+ * @see `ccnxInterestInterface_GetInterface`
+ */
+CCNxMessageInterface *ccnxTlvDictionary_GetMessageInterface(const CCNxTlvDictionary *dictionary);
+#endif // libccnx_ccnx_TlvDictionary_h
diff --git a/libccnx-common/ccnx/common/internal/ccnx_TlvError.c b/libccnx-common/ccnx/common/internal/ccnx_TlvError.c
new file mode 100755
index 00000000..0f07ab9e
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_TlvError.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/internal/ccnx_TlvError.h>
+
+struct error_messages {
+ CCNxTlvErrorCodes code;
+ const char *message;
+} TlvErrorMessages[] = {
+ { .code = TLV_ERR_NO_ERROR, .message = "No error" },
+ { .code = TLV_ERR_VERSION, .message = "Unsupported version" },
+ { .code = TLV_ERR_PACKETTYPE, .message = "Unsupported packet type" },
+ { .code = TLV_ERR_BEYOND_PACKET_END, .message = "Field goes beyond end of packet" },
+ { .code = TLV_ERR_TOO_LONG, .message = "Length too long for parent container" },
+ { .code = TLV_ERR_NOT_FIXED_SIZE, .message = "Fixed size Type wrong Length" },
+ { .code = TLV_ERR_DUPLICATE_FIELD, .message = "Duplicate field" },
+ { .code = TLV_ERR_EMPTY_SPACE, .message = "The sum of child TLVs did not add up to parent container length" },
+
+ // missing mandatory field errors
+ { .code = TLV_MISSING_MANDATORY, .message = "Missing mandatory field" },
+
+ { .code = TLV_ERR_DECODE, .message = "Decoding error" },
+
+ // end of list sentinel, the NULL determines the end of list
+ { .code = UINT16_MAX, .message = NULL }
+};
+
+
+const char *
+ccnxTlvErrors_ErrorMessage(CCNxTlvErrorCodes code)
+{
+ for (int i = 0; TlvErrorMessages[i].message != NULL; i++) {
+ if (TlvErrorMessages[i].code == code) {
+ return TlvErrorMessages[i].message;
+ }
+ }
+ return "No error message found";
+}
+
+// ==========================================================================
+
+struct ccnx_tlv_error {
+ CCNxTlvErrorCodes code;
+ const char *functionName;
+ int line;
+ size_t byteOffset;
+ unsigned refcount;
+ char *toString;
+};
+
+CCNxTlvError *
+ccnxTlvError_Create(CCNxTlvErrorCodes code, const char *func, int line, size_t byteOffset)
+{
+ CCNxTlvError *error = parcMemory_AllocateAndClear(sizeof(CCNxTlvError));
+ assertNotNull(error, "parcMemory_AllocateAndClear(%u) returned NULL", sizeof(CCNxTlvError));
+ error->code = code;
+ error->functionName = func;
+ error->line = line;
+ error->byteOffset = byteOffset;
+ error->toString = NULL; // computed on the fly
+ error->refcount = 1;
+ return error;
+}
+
+CCNxTlvError *
+ccnxTlvError_Acquire(CCNxTlvError *error)
+{
+ assertNotNull(error, "Parameter error must be non-null");
+ assertTrue(error->refcount > 0, "Parameter has 0 refcount, not valid");
+
+ error->refcount++;
+ return error;
+}
+
+void
+ccnxTlvError_Release(CCNxTlvError **errorPtr)
+{
+ assertNotNull(errorPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*errorPtr, "Parameter must derefernece to non-null pointer");
+ CCNxTlvError *error = *errorPtr;
+
+ assertTrue(error->refcount > 0, "Parameter has 0 refcount, not valid");
+ error->refcount--;
+ if (error->refcount == 0) {
+ if (error->toString) {
+ // this is asprintf generated
+ free(error->toString);
+ }
+ parcMemory_Deallocate((void **) &error);
+ }
+ *errorPtr = NULL;
+}
+
+size_t
+ccnxTlvError_GetByteOffset(const CCNxTlvError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return error->byteOffset;
+}
+
+
+CCNxTlvErrorCodes
+ccnxTlvError_GetErrorCode(const CCNxTlvError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return error->code;
+}
+
+const char *
+ccnxTlvError_GetFunction(const CCNxTlvError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return error->functionName;
+}
+
+int
+ccnxTlvError_GetLine(const CCNxTlvError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return error->line;
+}
+
+const char *
+ccnxTlvError_GetErrorMessage(const CCNxTlvError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ return ccnxTlvErrors_ErrorMessage(error->code);
+}
+
+const char *
+ccnxTlvError_ToString(CCNxTlvError *error)
+{
+ assertNotNull(error, "Parameter must be non-null");
+ if (error->toString) {
+ return error->toString;
+ }
+
+ asprintf(&error->toString, "TLV error: %s:%d offset %zu: %s",
+ error->functionName,
+ error->line,
+ error->byteOffset,
+ ccnxTlvError_GetErrorMessage(error));
+
+ return error->toString;
+}
diff --git a/libccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.c
new file mode 100755
index 00000000..d9f86895
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+static void
+_assertInvariants(const CCNxTlvDictionary *message)
+{
+ assertNotNull(message, "Parameter message must be non-null");
+}
+
+PARCBuffer *
+ccnxValidationFacadeV1_GetKeyId(const CCNxTlvDictionary *message)
+{
+ _assertInvariants(message);
+ return ccnxTlvDictionary_GetBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID);
+}
+
+CCNxLink *
+ccnxValidationFacadeV1_GetKeyName(const CCNxTlvDictionary *message)
+{
+ _assertInvariants(message);
+ CCNxLink *link = NULL;
+ CCNxName *name = ccnxTlvDictionary_GetName(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME);
+ if (name) {
+ PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID);
+ PARCBuffer *hash = ccnxTlvDictionary_GetBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH);
+
+ link = ccnxLink_Create(name, keyid, hash);
+ }
+ return link;
+}
+
+PARCBuffer *
+ccnxValidationFacadeV1_GetPublicKey(const CCNxTlvDictionary *message)
+{
+ _assertInvariants(message);
+ return ccnxTlvDictionary_GetBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY);
+}
+
+PARCBuffer *
+ccnxValidationFacadeV1_GetCertificate(const CCNxTlvDictionary *message)
+{
+ _assertInvariants(message);
+ return ccnxTlvDictionary_GetBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT);
+}
+
+PARCBuffer *
+ccnxValidationFacadeV1_GetPayload(const CCNxTlvDictionary *message)
+{
+ _assertInvariants(message);
+ return ccnxTlvDictionary_GetBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+}
+
+bool
+ccnxValidationFacadeV1_HasCryptoSuite(const CCNxTlvDictionary *message)
+{
+ bool hasCryptoSuite = false;
+ _assertInvariants(message);
+ if (ccnxTlvDictionary_IsValueInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE)) {
+ hasCryptoSuite = true;
+ }
+ return hasCryptoSuite;
+}
+
+PARCCryptoSuite
+ccnxValidationFacadeV1_GetCryptoSuite(const CCNxTlvDictionary *message)
+{
+ if (ccnxValidationFacadeV1_HasCryptoSuite(message)) {
+ return (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ }
+
+ trapUnexpectedState("Dictionary does not have a CryptoSuite set");
+}
+
+bool
+ccnxValidationFacadeV1_HasSigningTime(const CCNxTlvDictionary *message)
+{
+ bool hasSigningTime = false;
+ _assertInvariants(message);
+ if (ccnxTlvDictionary_IsValueInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME)) {
+ hasSigningTime = true;
+ }
+ return hasSigningTime;
+}
+
+uint64_t
+ccnxValidationFacadeV1_GetSigningTime(const CCNxTlvDictionary *message)
+{
+ if (ccnxValidationFacadeV1_HasSigningTime(message)) {
+ return ccnxTlvDictionary_GetInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME);
+ }
+
+ trapUnexpectedState("Dictionary does not have a CryptoSuite set");
+}
+
+// ===========================================================
+// Setters
+
+bool
+ccnxValidationFacadeV1_SetKeyId(CCNxTlvDictionary *message, const PARCBuffer *keyid)
+{
+ _assertInvariants(message);
+ return ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID, keyid);
+}
+
+bool
+ccnxValidationFacadeV1_SetKeyName(CCNxTlvDictionary *message, const CCNxLink *keyNameLink)
+{
+ _assertInvariants(message);
+ const CCNxName *name = ccnxLink_GetName(keyNameLink);
+ bool success = ccnxTlvDictionary_PutName(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME, name);
+ if (success) {
+ PARCBuffer *keyid = ccnxLink_GetKeyID(keyNameLink);
+ if (keyid) {
+ success = ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID, keyid);
+ }
+
+ if (success) {
+ PARCBuffer *hash = ccnxLink_GetContentObjectHash(keyNameLink);
+ success = ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH, hash);
+ }
+ }
+ return success;
+}
+
+bool
+ccnxValidationFacadeV1_SetKeyLocator(CCNxTlvDictionary *message, CCNxKeyLocator *keyLocator)
+{
+ bool success = true;
+ if (keyLocator) {
+ if (ccnxKeyLocator_IsKey(keyLocator)) {
+ PARCKey *key = ccnxKeyLocator_GetKey(keyLocator);
+ PARCBuffer *keybuffer = parcKey_GetKey(key);
+ success &= ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY, keybuffer);
+ } else if (ccnxKeyLocator_IsKeyLink(keyLocator)) {
+ CCNxLink *link = ccnxKeyLocator_GetKeyLink(keyLocator);
+ const CCNxName *name = ccnxLink_GetName(link);
+
+ // Support KeyId and COH as part of the keyname, case 1012
+ success &= ccnxTlvDictionary_PutName(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME, name);
+ } else {
+ trapUnrecoverableState("KeyLocator is not a known type");
+ }
+ }
+ return success;
+}
+
+bool
+ccnxValidationFacadeV1_SetPublicKey(CCNxTlvDictionary *message, const PARCBuffer *derEncodedKey)
+{
+ _assertInvariants(message);
+ return ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY, derEncodedKey);
+}
+
+bool
+ccnxValidationFacadeV1_SetCertificate(CCNxTlvDictionary *message, const PARCBuffer *derEncodedCertificate)
+{
+ _assertInvariants(message);
+ return ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT, derEncodedCertificate);
+}
+
+bool
+ccnxValidationFacadeV1_SetCryptoSuite(CCNxTlvDictionary *message, PARCCryptoSuite suite)
+{
+ _assertInvariants(message);
+ return ccnxTlvDictionary_PutInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite);
+}
+
+bool
+ccnxValidationFacadeV1_SetSigningTime(CCNxTlvDictionary *message, uint64_t signingTime)
+{
+ _assertInvariants(message);
+ return ccnxTlvDictionary_PutInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME, signingTime);
+}
+
+bool
+ccnxValidationFacadeV1_SetPayload(CCNxTlvDictionary *message, const PARCBuffer *validationPayload)
+{
+ _assertInvariants(message);
+ return ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, validationPayload);
+}
+
diff --git a/libccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.h
new file mode 100644
index 00000000..524efe7e
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_ValidationFacadeV1.h
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnx_ValidationFacadeV1.h
+ * @brief Generic functions to fetch/set the KeyId, PublicKey, Certificate, or validation payload
+ *
+ * The Validation Facade may be used directly on CCNxInterest or CCNxContentObject structures, for example:
+ *
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo");
+ * CCNxContentObject *object = ccnxContentObject_CreateWithNameAndPayload(name, NULL);
+ * ccnxName_Release(&name);
+ * // generate the KeyId
+ * ccnxValidationFacadeV1_SetKeyId(object, keyId);
+ * }
+ * @endcode
+ *
+ */
+
+#ifndef libccnx_ccnx_ValidationFacadeV1_h
+#define libccnx_ccnx_ValidationFacadeV1_h
+
+#include <parc/algol/parc_Buffer.h>
+
+#include <ccnx/common/ccnx_KeyLocator.h>
+
+#include <ccnx/common/ccnx_Link.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <parc/security/parc_CryptoSuite.h>
+
+
+// ===========================================================
+// Validation Algorithm
+
+#include <ccnx/common/validation/ccnxValidation_CRC32C.h>
+#include <ccnx/common/validation/ccnxValidation_EcSecp256K1.h>
+#include <ccnx/common/validation/ccnxValidation_HmacSha256.h>
+#include <ccnx/common/validation/ccnxValidation_RsaSha256.h>
+
+// ===========================================================
+// Getters
+
+/**
+ * If the Validation Algorithm has a KeyId field, return it if it exists
+ *
+ * Not all validation algorithms have a KeyId field. Only true signature algoritms, such as
+ * RSA or ECC should always have one. HMAC or other MACs often use the KeyId to identify a
+ * key agreed to via a key exchange protocol, so the meaning is only applicable to those parties.
+ * Integrity checks, such as CRC-32C, do not have a KeyId.
+ *
+ * @param [in] message An allocated dictionary
+ *
+ * @retval non-null The KeyId field of the Validation Algorithm
+ * @retval null KeyId is missing
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *wireFormat = // packet received from the network
+ * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat);
+ * PARCBuffer *keyid = ccnxValidationFacadeV1_GetKeyId(dictionary);
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxValidationFacadeV1_GetKeyId(const CCNxTlvDictionary *message);
+
+/**
+ * If the Validation Algorithm has a KeyName, return the embedded Link
+ *
+ * The returned CCNxLink is allocated on function call, so caller must
+ * release it when done.
+ *
+ * @param [in] message An allocated dictionary
+ *
+ * @retval non-null The KeyName link of the Validation Algorithm (must be released)
+ * @retval null KeyName is missing
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *wireFormat = // packet received from the network
+ * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat);
+ * CCNxLink *link = ccnxValidationFacadeV1_GetKeyName(dictionary);
+ * }
+ * @endcode
+ */
+CCNxLink *ccnxValidationFacadeV1_GetKeyName(const CCNxTlvDictionary *mesage);
+
+/**
+ * If the Validation Algorithm has a Public Key embedded, return it
+ *
+ * @param [in] message An allocated dictionary
+ *
+ * @retval non-null The KeyId field of the Validation Algorithm
+ * @retval null KeyId is missing
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *wireFormat = // packet received from the network
+ * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat);
+ * PARCBuffer *publicKeyDEREncoding = ccnxValidationFacadeV1_GetPublicKey(dictionary);
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxValidationFacadeV1_GetPublicKey(const CCNxTlvDictionary *message);
+
+/**
+ * If the Validation Algorithm has a Certificate embedded, return it
+ *
+ * @param [in] message An allocated dictionary
+ *
+ * @retval non-null The Certificate field of the Validation Algorithm
+ * @retval null KeyId is missing
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *wireFormat = // packet received from the network
+ * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat);
+ * PARCBuffer *x509certDEREncoding = ccnxValidationFacadeV1_GetCertificate(dictionary);
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxValidationFacadeV1_GetCertificate(const CCNxTlvDictionary *message);
+
+/**
+ * Returns the Validation Payload, if present.
+ *
+ * The validation payload is the actual bytes of the signature or authentication code or
+ * integrity check. it's format will be specific to the ValidationAlgorithm.
+ *
+ * @param [in] message An allocated dictionary
+ *
+ * @retval non-null The validation payload
+ * @retval null Validation payload does not exist
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *wireFormat = // packet received from the network
+ * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat);
+ * PARCBuffer *validationPayload = ccnxValidationFacadeV1_GetPayload(dictionary);
+ * }
+ * @endcode
+ */
+PARCBuffer *ccnxValidationFacadeV1_GetPayload(const CCNxTlvDictionary *message);
+
+/**
+ * Determines if the packet specified a supported crypto suite
+ *
+ * @param [in] message An allocated dictionary
+ *
+ * @retval true There is a valid crypto suite specified
+ * @retval false There is not a valid crypto suite specified
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *wireFormat = // packet received from the network
+ * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat);
+ * if (ccnxValidationFacadeV1_HasCryptoSuite(dictionary)) {
+ * PARCCryptoSuite suite = ccnxValidationFacadeV1_GetCryptoSuite(dictionary);
+ * // process the validation alg
+ * }
+ * }
+ * @endcode
+ */
+bool ccnxValidationFacadeV1_HasCryptoSuite(const CCNxTlvDictionary *message);
+
+/**
+ * Returns the Validation Algorithm specified in the packet
+ *
+ * If the packet specified a supported crypto suite, return the suite. If
+ * it is not a supported algorithm, function all assert an error. You must use
+ * ccnxValidationFacadeV1_HasCryptoSuite() to determine if there is a supported crypto suite.
+ *
+ * An unsupported crypto suite's entire TLV container is put in the CustomField section of
+ * the dictionary and you can retrieve it from there if you know the type or iterate the list.
+ *
+ * @param [in] message An allocated dictionary
+ *
+ * @return value The crypto suite
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *wireFormat = // packet received from the network
+ * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat);
+ * if (ccnxValidationFacadeV1_HasCryptoSuite(dictionary)) {
+ * PARCCryptoSuite suite = ccnxValidationFacadeV1_GetCryptoSuite(dictionary);
+ * // process the validation alg
+ * }
+ * }
+ * @endcode
+ */
+PARCCryptoSuite ccnxValidationFacadeV1_GetCryptoSuite(const CCNxTlvDictionary *message);
+
+/**
+ * Determines if the packet specified a signing time
+ *
+ * @param [in] message An allocated dictionary
+ *
+ * @retval true There is a signing time in the validation algorithm
+ * @retval false There is not a signing time
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *wireFormat = // packet received from the network
+ * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat);
+ * if (ccnxValidationFacadeV1_HasSigningTime(dictionary)) {
+ * uint64_t signingTime = ccnxValidationFacadeV1_GetSigningTime(dictionary);
+ * // process the signing time
+ * }
+ * }
+ * @endcode
+ */
+bool ccnxValidationFacadeV1_HasSigningTime(const CCNxTlvDictionary *message);
+
+/**
+ * Retruns the Validation Algorithm specified in the packet
+ *
+ * If the packet has a Signing Time in the Validation Algorithm, return that value. If
+ * it is not, function all assert an error. You must use
+ * ccnxValidationFacadeV1_HasSigningTime() to determine if there is a
+ * signing time.
+ *
+ * The signing time is UTC milli-seconds since the epoch.
+ *
+ * @param [in] message An allocated dictionary
+ *
+ * @return value The signing time in UTC milli-seconds since the epoch.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *wireFormat = // packet received from the network
+ * CCNxTlvDictionary *dictionary = ccnxCodecTlvPacket_Decode(wireFormat);
+ * if (ccnxValidationFacadeV1_HasSigningTime(dictionary)) {
+ * uint64_t signingTime = ccnxValidationFacadeV1_GetSigningTime(dictionary);
+ * // process the signing time
+ * }
+ * }
+ * @endcode
+ */
+uint64_t ccnxValidationFacadeV1_GetSigningTime(const CCNxTlvDictionary *message);
+
+// ===========================================================
+// Setters
+
+/**
+ * Sets the KeyId attribute of the dictionary
+ *
+ * The KeyId is a mandatory field for validation algorithms that use a key, such
+ * as HMAC or RSA or ECC.
+ *
+ * Normally, one uses a function in the ccnxValidation algoirthm to set this value
+ * such as bool ccnxValidationHmacSha256_Set(CCNxTlvDictionary *message, const PARCBuffer *keyid).
+ *
+ * @param [in] message The dictionary to set the value in
+ * @param [in] keyid The encoded value of the keyid
+ *
+ * @retval true Value set in the dictionary
+ * @retval false Error, likely the value was already set
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo");
+ * CCNxContentObject *object = ccnxContentObject_CreateWithNameAndPayload(name, NULL);
+ * ccnxName_Release(&name);
+ *
+ * PARCBuffer *secretKey = parcBuffer_Wrap("password", 8, 0, 8);
+ * PARCSigner *signer = ccnxValidationHmacSha256_CreateSigner(secretKey);
+ *
+ * PARCKeyId *keyid = parcSigner_CreateKeyId(signer);
+ * const PARCBuffer *keyIdBytes = parcKeyId_GetKeyId(keyid);
+ * ccnxValidationFacadeV1_SetKeyId(object, keyIdBytes);
+ * parcKeyId_Release(&keyid);
+ *
+ * // continue with signer and dictionary
+ * }
+ * @endcode
+ */
+bool ccnxValidationFacadeV1_SetKeyId(CCNxTlvDictionary *message, const PARCBuffer *keyid);
+
+
+/**
+ * Stores the KeyLocator in the standard Dictionary places for use by the standard Getters
+ *
+ * If the Validator does not need any special handing of a KeyLocator, this function
+ * will store the keylocator in the default dictionary entries for use by the standard getters.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxValidationFacadeV1_SetKeyLocator(CCNxTlvDictionary *message, CCNxKeyLocator *keyLocator);
+
+/**
+ * Stores the KeyName in the standard Dictionary places for use by the standard Getters
+ *
+ * Stores the fields from the Link in the dictionary.
+ *
+ * @param [in] message The message to update
+ * @param [in] keyNameLink The link to put in the dictionary
+ *
+ * @retval true Values successfully added to dictionary
+ * @retval false An error (likely a duplicate value)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxValidationFacadeV1_SetKeyName(CCNxTlvDictionary *message, const CCNxLink *keyNameLink);
+
+/**
+ * Embeds the DER encoded public key in the Validation Algorithm
+ *
+ * If this field is not set, the public key will not be placed in the
+ * validation algorithm.
+ *
+ * @param [in] message The message to update
+ * @param [in] derEncodedKey The DER encoded public key to put in the dictionary
+ *
+ * @retval true Value successfully added to dictionary
+ * @retval false An error (likely a duplicate value)
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo");
+ * CCNxContentObject *object = ccnxContentObject_CreateWithNameAndPayload(name, NULL);
+ * ccnxName_Release(&name);
+ *
+ * PARCSigner *signer = parcSigner_Create(parcPublicKeySignerPkcs12Store_Open("keystore.p12", "password", PARCCryptoHashType_SHA256));
+ *
+ * PARCBuffer *publicKey = parcSigner_GetDEREncodedPublicKey(signer);
+ *
+ * ccnxValidationFacadeV1_SetPublicKey(object, publicKey);
+ *
+ * // continue with signer and dictionary
+ * } * @endcode
+ */
+bool ccnxValidationFacadeV1_SetPublicKey(CCNxTlvDictionary *message, const PARCBuffer *derEncodedKey);
+
+/**
+ * Embeds the DER encoded public key in the Validation Algorithm
+ *
+ * If this field is not set, the public key will not be placed in the
+ * validation algorithm.
+ *
+ * @param [in] message The message to update
+ * @param [in] derEncodedCertificate The DER encoded public key to put in the dictionary
+ *
+ * @retval true Value successfully added to dictionary
+ * @retval false An error (likely a duplicate value)
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/foo");
+ * CCNxContentObject *object = ccnxContentObject_CreateWithNameAndPayload(name, NULL);
+ * ccnxName_Release(&name);
+ *
+ * PARCSigner *signer = parcSigner_Create(parcPublicKeySignerPkcs12Store_Open("keystore.p12", "password", PARCCryptoHashType_SHA256));
+ *
+ * PARCBuffer *cert = parcSigner_GetDEREncodedCertificate(signer);
+ *
+ * ccnxValidationFacadeV1_SetPublicKey(object, cert);
+ *
+ * // continue with signer and dictionary
+ * } * @endcode
+ */
+bool ccnxValidationFacadeV1_SetCertificate(CCNxTlvDictionary *message, const PARCBuffer *derEncodedCertificate);
+
+/**
+ * Sets the crypto suite in the dictionary
+ *
+ * It is not necessary to set the crypto suite if the packet is encoded with a Signer,
+ * as the crypto suite will be derived from the signer.
+ *
+ * Normally, one uses a function in the ccnxValidation algoirthm to set this value
+ * such as bool ccnxValidationHmacSha256_Set(CCNxTlvDictionary *message, const PARCBuffer *keyid).
+ *
+ * @param [in] message The message to update
+ * @param [in] suite The cryptosuite value to set in the packet
+ *
+ * @retval true The crypto suite was set
+ * @retval false The crypto suite was not set (not supported by V1 or other error)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxValidationFacadeV1_SetCryptoSuite(CCNxTlvDictionary *message, PARCCryptoSuite suite);
+
+/**
+ * Sets the signing time in the dictionary
+ *
+ * The signing time represents when the signature is created. It is sometimes used for
+ * replay attack prevention. It is the UTC time in milli-seconds since the epoch (i.e. a posix time).
+ *
+ * If the signing time is not specified in the dictionary, it will be automatically created
+ * based on the system clock when the signature is generated (this assumes the system clock
+ * and timezone are correctly set).
+ *
+ * @param [in] message The message to update
+ * @param [in] signingTime UTC time since the epoch in milli-seconds
+ *
+ * @retval true The value was set
+ * @retval false The value was not set (likely a duplicate value)
+ *
+ * Example:
+ * @code
+ * @endcode
+ */
+bool ccnxValidationFacadeV1_SetSigningTime(CCNxTlvDictionary *message, uint64_t signingTime);
+
+/**
+ * Saves the validation payload in the dictionary
+ *
+ * The validation payload is the output of the validation algorithm, i.e.
+ * the 32-bit CRC32C checksum or the RSA signature. Usually the Codec is setting this
+ * value after it has generated the wire format. If this value is set prior to encoding,
+ * this value will be used regardless if it is correct or not.
+ *
+ * You can only save the payload once per dictionary.
+ *
+ * @param [in] message The message to update
+ * @param [in] validationPayload The payload to put in the packet
+ *
+ * @return true Payload saved
+ * @return false Payload was already set or other error
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSignature *signature = ccnxCodecTlvEncoder_ComputeSignature(encoder);
+ * PARCBuffer *sigbits = parcSignature_GetSignature(signature);
+ *
+ * // this creates its own reference to sigbits
+ * ccnxValidationFacadeV1_SetPayload(packetDictionary, sigbits);
+ *
+ * parcSignature_Release(&signature);
+ * parcBuffer_Release(&sigbits);
+ * }
+ * @endcode
+ */
+bool ccnxValidationFacadeV1_SetPayload(CCNxTlvDictionary *message, const PARCBuffer *validationPayload);
+
+#endif // libccnx_ccnx_ValidationFacadeV1_h
diff --git a/libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.c b/libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.c
new file mode 100644
index 00000000..daf851c7
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_FileOutputStream.h>
+
+#include <ccnx/common/internal/ccnx_WireFormatMessageInterface.h>
+#include <ccnx/common/internal/ccnx_WireFormatFacadeV1.h>
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+
+
+static CCNxTlvDictionary *
+_ccnxWireFormatFacadeV1_FromInterestPacketType(const PARCBuffer *wireFormat)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, wireFormat);
+ return dictionary;
+}
+
+static CCNxTlvDictionary *
+_ccnxWireFormatFacadeV1_FromInterestPacketTypeIoVec(const CCNxCodecNetworkBufferIoVec *vec)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxTlvDictionary_PutIoVec(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, vec);
+ return dictionary;
+}
+
+static CCNxTlvDictionary *
+_ccnxWireFormatFacadeV1_FromInterestReturnPacketType(const PARCBuffer *wireFormat)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn();
+ ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, wireFormat);
+ return dictionary;
+}
+
+static CCNxTlvDictionary *
+_ccnxWireFormatFacadeV1_FromContentObjectPacketType(const PARCBuffer *wireFormat)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, wireFormat);
+ return dictionary;
+}
+
+static CCNxTlvDictionary *
+_ccnxWireFormatFacadeV1_FromControlPacketType(const PARCBuffer *wireFormat)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+ ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, wireFormat);
+ return dictionary;
+}
+
+static CCNxCodecSchemaV1InterestHeader *
+_getWireFormatFixedHeader(CCNxTlvDictionary *dictionary)
+{
+ // Currently there is only one of either a PARCBuffer or an IoVec ...
+
+ CCNxCodecSchemaV1InterestHeader *header = NULL;
+
+ // Update attached iovec
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxWireFormatMessage_GetIoVec(dictionary);
+ if (iovec) {
+ assertTrue(ccnxCodecNetworkBufferIoVec_Length(iovec) >= sizeof(CCNxCodecSchemaV1InterestHeader),
+ "IoVector smaller than required for message header");
+ const struct iovec *iov = ccnxCodecNetworkBufferIoVec_GetArray(iovec);
+ assertTrue(iov[0].iov_len >= sizeof(CCNxCodecSchemaV1InterestHeader),
+ "Header not contained in first element of io vector");
+ header = iov[0].iov_base;
+ } else {
+ // Update attached buffer
+ PARCBuffer *wireFormatBuffer = ccnxWireFormatMessage_GetWireFormatBuffer(dictionary);
+ if (wireFormatBuffer) {
+ header = parcBuffer_Overlay(wireFormatBuffer, 0);
+ }
+ }
+
+ return header;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_SetHopLimit(CCNxTlvDictionary *dictionary, uint32_t hopLimit)
+{
+ bool result = false;
+
+ CCNxCodecSchemaV1InterestHeader *header = _getWireFormatFixedHeader(dictionary);
+ if (header != NULL) {
+ header->hopLimit = hopLimit;
+ result = true;
+ }
+ return result;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_ConvertInterestToInterestReturn(CCNxTlvDictionary *dictionary, uint8_t code)
+{
+ bool result = false;
+
+ CCNxCodecSchemaV1InterestHeader *header = _getWireFormatFixedHeader(dictionary);
+ if (header != NULL) {
+ header->returnCode = code;
+ header->packetType = CCNxCodecSchemaV1Types_PacketType_InterestReturn;
+ result = true;
+ }
+ return result;
+}
+
+static CCNxTlvDictionary *
+_ccnxWireFormatFacadeV1_CreateFromV1(const PARCBuffer *wireFormat)
+{
+ CCNxTlvDictionary *dictionary = NULL;
+ uint8_t packetType = parcBuffer_GetAtIndex(wireFormat, 1);
+ switch (packetType) {
+ case CCNxCodecSchemaV1Types_PacketType_ContentObject:
+ dictionary = _ccnxWireFormatFacadeV1_FromContentObjectPacketType(wireFormat);
+ break;
+ case CCNxCodecSchemaV1Types_PacketType_Control:
+ dictionary = _ccnxWireFormatFacadeV1_FromControlPacketType(wireFormat);
+ break;
+ case CCNxCodecSchemaV1Types_PacketType_Interest:
+ dictionary = _ccnxWireFormatFacadeV1_FromInterestPacketType(wireFormat);
+ break;
+ case CCNxCodecSchemaV1Types_PacketType_InterestReturn:
+ dictionary = _ccnxWireFormatFacadeV1_FromInterestReturnPacketType(wireFormat);
+ break;
+ default:
+ // will return NULL
+ break;
+ }
+ return dictionary;
+}
+
+static PARCBuffer *
+_ccnxWireFormatFacadeV1_GetWireFormatBuffer(const CCNxTlvDictionary *dictionary)
+{
+ PARCBuffer *wireFormat = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat);
+ return wireFormat;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_PutWireFormatBuffer(CCNxTlvDictionary *dictionary, PARCBuffer *wireFormat)
+{
+ bool success = ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, wireFormat);
+ return success;
+}
+
+static CCNxCodecNetworkBufferIoVec *
+_ccnxWireFormatFacadeV1_GetIoVec(const CCNxTlvDictionary *dictionary)
+{
+ CCNxCodecNetworkBufferIoVec *vec = ccnxTlvDictionary_GetIoVec(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat);
+ return vec;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_PutIoVec(CCNxTlvDictionary *dictionary, CCNxCodecNetworkBufferIoVec *vec)
+{
+ bool success = ccnxTlvDictionary_PutIoVec(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat, vec);
+ return success;
+}
+
+static void
+_ccnxWireFormatFacadeV1_WriteToFile(const CCNxTlvDictionary *dictionary, const char *filename)
+{
+ int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
+ PARCFileOutputStream *fos = parcFileOutputStream_Create(fd);
+
+ PARCBuffer *wireFormat = _ccnxWireFormatFacadeV1_GetWireFormatBuffer(dictionary);
+ if (wireFormat) {
+ parcFileOutputStream_Write(fos, wireFormat);
+ parcBuffer_Rewind(wireFormat);
+ }
+
+ // this will close the file descriptor
+ parcFileOutputStream_Release(&fos);
+}
+
+static bool
+_ccnxWireFormatFacadeV1_SetProtectedRegionStart(CCNxTlvDictionary *dictionary, size_t startPosition)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ // ccnx packets work on 16-bit lengths
+ assertTrue(startPosition <= UINT16_MAX, "Start position beyond UINT16_MAX: %zu", startPosition);
+
+ bool success = ccnxTlvDictionary_PutInteger(dictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedStart,
+ startPosition);
+ return success;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_SetProtectedRegionLength(CCNxTlvDictionary *dictionary, size_t length)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ // ccnx packets work on 16-bit lengths
+ assertTrue(length <= UINT16_MAX, "Length position beyond UINT16_MAX: %zu", length);
+
+ bool success = ccnxTlvDictionary_PutInteger(dictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedLength,
+ length);
+ return success;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_SetContentObjectHashRegionStart(CCNxTlvDictionary *dictionary, size_t startPosition)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ // ccnx packets work on 16-bit lengths
+ assertTrue(startPosition <= UINT16_MAX, "Start position beyond UINT16_MAX: %zu", startPosition);
+
+ bool success = ccnxTlvDictionary_PutInteger(dictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionStart,
+ startPosition);
+ return success;
+}
+
+static bool
+_ccnxWireFormatFacadeV1_SetContentObjectHashRegionLength(CCNxTlvDictionary *dictionary, size_t length)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ // ccnx packets work on 16-bit lengths
+ assertTrue(length <= UINT16_MAX, "Length position beyond UINT16_MAX: %zu", length);
+
+ bool success = ccnxTlvDictionary_PutInteger(dictionary,
+ CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionLength,
+ length);
+ return success;
+}
+
+
+/*
+ * Compute the hash over the specified region. This is a static function, so we know the caller
+ * has verified all the parameters before giving them to us.
+ * The caller must also verify that (start + length <= totalLength).
+ *
+ * As we walk through the iovecs, the variables will look like this
+ * +-----------+-----------+-----------+-----------+-----------+
+ * iov[0] iov[1] iov[2] iov[3]
+ * +-----------+-----------+-----------+-----------+-----------+
+ * ^ ^ ^ ^
+ * | | | |
+ * | start | end
+ * iovStart iovEnd
+ * |-------|---|
+ * offset
+ * remaining
+ *
+ * +-----------+-----------+-----------+-----------+-----------+
+ * iov[0] iov[1] iov[2] iov[3]
+ * +-----------+-----------+-----------+-----------+-----------+
+ * ^ ^ ^
+ * | | |
+ * start | end
+ * iovStart iovEnd
+ * |-----------|
+ * offset (0)
+ * remaining (iov_len)
+ *
+ * +-----------+-----------+-----------+-----------+-----------+
+ * iov[0] iov[1] iov[2] iov[3]
+ * +-----------+-----------+-----------+-----------+-----------+
+ * ^ ^
+ * | |
+ * start end
+ * iovStart iovEnd
+ * |------|
+ * offset (0)
+ * remaining (end-start)
+ *
+ */
+static PARCCryptoHash *
+_hashProtectedRegionIoVec(CCNxCodecNetworkBufferIoVec *vec, PARCCryptoHasher *hasher, size_t start, size_t length)
+{
+ int failure = parcCryptoHasher_Init(hasher);
+ assertFalse(failure, "Error initializing the hasher");
+
+ const struct iovec *iov = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+ int iovcnt = ccnxCodecNetworkBufferIoVec_GetCount(vec);
+
+ // iovStart is the beginning position of the current iovec
+ size_t iovStart = 0;
+ size_t end = start + length;
+
+ // Once iovStart is past end, we no longer need to loop, we're done
+ for (int i = 0; i < iovcnt && iovStart < end; i++) {
+ size_t iovEnd = iovStart + iov[i].iov_len;
+ iovEnd = (iovEnd > end) ? end : iovEnd;
+
+ // is "start" contained in this iovec?
+ if (iovStart <= start && start < iovEnd) {
+ size_t offset = start - iovStart;
+ size_t remaining = iovEnd - start;
+
+ failure = parcCryptoHasher_UpdateBytes(hasher, (const void *) ((uint8_t *) iov[i].iov_base + offset), remaining);
+ assertFalse(failure, "Error updating hasher iovec %d offset %zu remaining %zu", i, offset, remaining)
+ {
+ ccnxCodecNetworkBufferIoVec_Display(vec, 3);
+ }
+
+ // keep moving start to the next iovec
+ start += remaining;
+ }
+
+ iovStart += iov[i].iov_len;
+ }
+
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+
+ return hash;
+}
+
+
+/*
+ * Compute the hash over the specified region. This is a static function, so we know the caller
+ * has verified all the parameters before giving them to us.
+ * The caller must also verify that (start + length <= parcBuffer_Limit).
+ *
+ * +-----------+-----------+-----------+-----------+-----------+
+ * PARCBuffer
+ * +-----------+-----------+-----------+-----------+-----------+
+ * ^ ^ ^ ^
+ * | | | |
+ * 0 start end Limit
+ */
+static PARCCryptoHash *
+_ccnxWireFormatFacadeV1_ComputeBufferHash(PARCBuffer *wireFormat, PARCCryptoHasher *hasher, size_t start, size_t length)
+{
+ int failure = parcCryptoHasher_Init(hasher);
+ assertTrue(failure == 0, "Error initializing the hasher");
+
+ parcBuffer_SetPosition(wireFormat, start);
+ uint8_t *overlay = parcBuffer_Overlay(wireFormat, 0);
+
+ failure = parcCryptoHasher_UpdateBytes(hasher, overlay, length);
+ assertTrue(failure == 0, "Error updating hasher start %zu length %zu", start, length)
+ {
+ parcBuffer_Display(wireFormat, 3);
+ }
+
+ parcBuffer_Rewind(wireFormat);
+
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ return hash;
+}
+
+static PARCCryptoHash *
+_ccnxWireFormatFacadeV1_HashProtectedRegion(const CCNxTlvDictionary *dictionary, PARCCryptoHasher *hasher)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-null");
+ assertNotNull(hasher, "Parameter hasher must be non-null");
+
+ PARCCryptoHash *hash = NULL;
+
+ if (ccnxTlvDictionary_IsValueInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedStart)) {
+ if (ccnxTlvDictionary_IsValueInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedLength)) {
+ size_t startPosition = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedStart);
+ size_t length = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedLength);
+
+ CCNxCodecNetworkBufferIoVec *vec = _ccnxWireFormatFacadeV1_GetIoVec(dictionary);
+ if (vec) {
+ size_t totalLength = ccnxCodecNetworkBufferIoVec_Length(vec);
+ if (startPosition + length <= totalLength) {
+ hash = _hashProtectedRegionIoVec(vec, hasher, startPosition, length);
+ }
+ } else {
+ PARCBuffer *wireFormat = _ccnxWireFormatFacadeV1_GetWireFormatBuffer(dictionary);
+ if (wireFormat) {
+ size_t totalLength = parcBuffer_Remaining(wireFormat);
+ if (startPosition + length <= totalLength) {
+ hash = _ccnxWireFormatFacadeV1_ComputeBufferHash(wireFormat, hasher, startPosition, length);
+ }
+ }
+ }
+ }
+ }
+
+ return hash;
+}
+
+
+static PARCCryptoHash *
+_ccnxWireFormatFacadeV1_ComputeContentObjectHash(CCNxTlvDictionary *dictionary)
+{
+ // This assumes the dictionary has been passed through something like the V1 packet decoder,
+ // (e.g. ccnxCodecSchemaV1PacketDecoder_Decode) and has had the protected region extents set.
+ // This will be the case for Athena. Metis has its own TLV parsing.
+
+ assertTrue(ccnxTlvDictionary_IsContentObject(dictionary) || ccnxTlvDictionary_IsManifest(dictionary), "Message must be a ContentObject or Manifest");
+
+ PARCCryptoHash *result = NULL;
+
+ if (ccnxTlvDictionary_IsValueInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionStart)
+ && ccnxTlvDictionary_IsValueInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionLength)) {
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ size_t startPosition = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionStart);
+ size_t length = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionLength);
+
+ CCNxCodecNetworkBufferIoVec *vec = _ccnxWireFormatFacadeV1_GetIoVec(dictionary);
+ if (vec) {
+ size_t totalLength = ccnxCodecNetworkBufferIoVec_Length(vec);
+ if (startPosition + length <= totalLength) {
+ result = _hashProtectedRegionIoVec(vec, hasher, startPosition, length);
+ }
+ } else {
+ PARCBuffer *wireFormat = _ccnxWireFormatFacadeV1_GetWireFormatBuffer(dictionary);
+ if (wireFormat) {
+ size_t totalLength = parcBuffer_Remaining(wireFormat);
+ if (startPosition + length <= totalLength) {
+ result = _ccnxWireFormatFacadeV1_ComputeBufferHash(wireFormat, hasher, startPosition, length);
+ }
+ }
+ }
+ parcCryptoHasher_Release(&hasher);
+ }
+
+ return result; // Could be NULL
+}
+
+
+/**
+ * `CCNxWireFormatFacadeV1_Implementation` is the structure containing the pointers to the
+ * V1 schema WireFormatMessage implementation.
+ */
+CCNxWireFormatMessageInterface CCNxWireFormatFacadeV1_Implementation = {
+ .description = "CCNxWireFormatFacadeV1_Implementation",
+
+ .create = &_ccnxWireFormatFacadeV1_CreateFromV1,
+
+ .fromInterestPacketType = &_ccnxWireFormatFacadeV1_FromInterestPacketType,
+
+ .fromInterestPacketTypeIoVec = &_ccnxWireFormatFacadeV1_FromInterestPacketTypeIoVec,
+
+ .fromContentObjectPacketType = &_ccnxWireFormatFacadeV1_FromContentObjectPacketType,
+
+ .fromControlPacketType = &_ccnxWireFormatFacadeV1_FromControlPacketType,
+
+ .getWireFormatBuffer = &_ccnxWireFormatFacadeV1_GetWireFormatBuffer,
+
+ .getIoVec = &_ccnxWireFormatFacadeV1_GetIoVec,
+
+ .putWireFormatBuffer = &_ccnxWireFormatFacadeV1_PutWireFormatBuffer,
+
+ .putIoVec = &_ccnxWireFormatFacadeV1_PutIoVec,
+
+ .writeToFile = &_ccnxWireFormatFacadeV1_WriteToFile,
+
+ .setProtectedRegionStart = &_ccnxWireFormatFacadeV1_SetProtectedRegionStart,
+
+ .setProtectedRegionLength = &_ccnxWireFormatFacadeV1_SetProtectedRegionLength,
+
+ .hashProtectedRegion = &_ccnxWireFormatFacadeV1_HashProtectedRegion,
+
+ .setContentObjectHashRegionStart = &_ccnxWireFormatFacadeV1_SetContentObjectHashRegionStart,
+
+ .setContentObjectHashRegionLength = &_ccnxWireFormatFacadeV1_SetContentObjectHashRegionLength,
+
+ .computeContentObjectHash = &_ccnxWireFormatFacadeV1_ComputeContentObjectHash,
+
+ .setHopLimit = &_ccnxWireFormatFacadeV1_SetHopLimit,
+
+ .convertInterestToInterestReturn = &_ccnxWireFormatFacadeV1_ConvertInterestToInterestReturn,
+};
diff --git a/libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.h b/libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.h
new file mode 100755
index 00000000..cd888062
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_WireFormatFacadeV1.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * @file ccnx_WireFormatFacadeV1.h
+ * @ingroup Utility
+ *
+ * A WireFormat facade will set/get the wire format representation of a message from the
+ * dictionary.
+ *
+ * One may also create a message dictionary only with a wire format, not specifying the actual message type.
+ * This occurs mostly at the lowest layer that receives a network buffer and does not yet know what sort of message it holds.
+ *
+ * This facade is used by the Forwarder Connector to create the original dictionary
+ * at the bottom of the stack on receive. It is also used by the Codec component to set
+ * the wireformat to encode a packet.
+ *
+ * If an application has a pre-encoded packet, it can create an empty dictionary and set the wire format
+ * then send that down the stack.
+ *
+ */
+#ifndef libccnx_ccnx_WireFormatFacadeV1_h
+#define libccnx_ccnx_WireFormatFacadeV1_h
+
+
+#include <ccnx/common/internal/ccnx_WireFormatMessageInterface.h>
+
+extern CCNxWireFormatMessageInterface CCNxWireFormatFacadeV1_Implementation;
+#endif // libccnx_ccnx_WireFormatFacadeV1_h
diff --git a/libccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.c b/libccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.c
new file mode 100755
index 00000000..bb698eb4
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/internal/ccnx_WireFormatMessageInterface.h>
+
+
+CCNxWireFormatMessageInterface *
+ccnxWireFormatMessageInterface_GetInterface(const CCNxTlvDictionary *dictionary)
+{
+ CCNxWireFormatMessageInterface *impl = NULL;
+
+ int schemaVersion = ccnxTlvDictionary_GetSchemaVersion(dictionary);
+
+ switch (schemaVersion) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ impl = &CCNxWireFormatFacadeV1_Implementation;
+ break;
+ default:
+ trapUnexpectedState("Unknown SchemaVersion encountered in ccnxWireFormatMessageInterface_GetInterface()");
+ break;
+ }
+
+ // We do not set the implementation pointer in the dictionary here. That is only done when accessing the dictionary
+ // as a CCNxContentObject, CCNxInterest, CCNxInterestReturn, or CCNxControlMessage.
+
+ return impl;
+}
diff --git a/libccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.h b/libccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.h
new file mode 100755
index 00000000..2efc2194
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/ccnx_WireFormatMessageInterface.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @brief The definition of the interface used to call into a CCNxWireFormatFacade implementation.
+ *
+ */
+
+#ifndef CCNx_Common_ccnx_internal_WireFormatMessageInterface_h
+#define CCNx_Common_ccnx_internal_WireFormatMessageInterface_h
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+typedef struct ccnx_wireformatmessage_interface {
+ char *description; // A human-readable label for this implementation
+
+ /** @see ccnxWireFormatMessage_Create */
+ CCNxTlvDictionary *(*create)(const PARCBuffer * wireFormat);
+
+ /** @see ccnxWireFormatMessage_FromInterestPacketType */
+ CCNxTlvDictionary *(*fromInterestPacketType)(const PARCBuffer * wireFormat);
+
+ /** @see ccnxWireFormatMessage_FromInterestPacketTypeIoVec */
+ CCNxTlvDictionary *(*fromInterestPacketTypeIoVec)(const CCNxCodecNetworkBufferIoVec * vec);
+
+ /** @see ccnxWireFormatMessage_FromContentObjectPacketType */
+ CCNxTlvDictionary *(*fromContentObjectPacketType)(const PARCBuffer * wireFormat);
+
+ /** @see ccnxWireFormatMessage_FromControlPacketType */
+ CCNxTlvDictionary *(*fromControlPacketType)(const PARCBuffer * wireFormat);
+
+ /** @see ccnxWireFormatMessage_GetWireFormatBuffer */
+ PARCBuffer *(*getWireFormatBuffer)(const CCNxTlvDictionary * dictionary);
+
+ /** @see ccnxWireFormatMessage_GetIoVec */
+ CCNxCodecNetworkBufferIoVec *(*getIoVec)(const CCNxTlvDictionary * dictionary);
+
+ /** @see ccnxWireFormatMessage_PutWireFormatBuffer */
+ bool (*putWireFormatBuffer)(CCNxTlvDictionary *dictionary, PARCBuffer *buffer);
+
+ /** @see ccnxWireFormatMessage_PutIoVec */
+ bool (*putIoVec)(CCNxTlvDictionary *dictionary, CCNxCodecNetworkBufferIoVec *vec);
+
+ /** @see ccnxWireFormatMessage_WriteToFile */
+ void (*writeToFile)(const CCNxTlvDictionary *dictionary, const char *filename);
+
+ /** @see ccnxWireFormatMessage_SetProtectedRegionStart */
+ bool (*setProtectedRegionStart)(CCNxTlvDictionary *dictionary, size_t startPosition);
+
+ /** @see ccnxWireFormatMessage_SetProtectedRegionLength */
+ bool (*setProtectedRegionLength)(CCNxTlvDictionary *dictionary, size_t length);
+
+ /** @see ccnxWireFormatMessage_SetContentObjectHashRegionStart */
+ bool (*setContentObjectHashRegionStart)(CCNxTlvDictionary *dictionary, size_t startPosition);
+
+ /** @see ccnxWireFormatMessage_SetContentObjectHashRegionLength */
+ bool (*setContentObjectHashRegionLength)(CCNxTlvDictionary *dictionary, size_t length);
+
+ /** @see ccnxWireFormatMessage_HashProtectedRegion */
+ PARCCryptoHash *(*hashProtectedRegion)(const CCNxTlvDictionary * dictionary, PARCCryptoHasher * hasher);
+
+ /** @see ccnxWireFormatMessage_SetHopLimit */
+ bool (*setHopLimit)(CCNxTlvDictionary *dictionary, uint32_t hopLimit);
+
+ /** @see ccnxWireFormatMessage_AssertValid*/
+ void (*assertValid)(const CCNxTlvDictionary *dictionary);
+
+ /** @see ccnxWireFormatMessage_CreateContentObjectHash */
+ PARCCryptoHash *(*computeContentObjectHash)(CCNxTlvDictionary * dictionary);
+
+ /** @see ccnxWireFormatMessage_ConvertInterestToInterestReturn */
+ bool (*convertInterestToInterestReturn)(CCNxTlvDictionary *dictionary, uint8_t returnCode);
+} CCNxWireFormatMessageInterface;
+
+/**
+ * The SchemaV0 WireFormatMessage implementaton
+ */
+extern CCNxWireFormatMessageInterface CCNxWireFormatFacadeV0_Implementation;
+
+/**
+ * The SchemaV1 WireFormatMessage implementaton
+ */
+extern CCNxWireFormatMessageInterface CCNxWireFormatFacadeV1_Implementation;
+
+/**
+ * Given a CCNxTlvDictionary representing a CCNxWireFormatMessage, return the address of the CCNxWireFormatMessageInterface
+ * instance that should be used to access the WireFormatMessage.
+ *
+ * @param interestDictionary - a {@link CCNxTlvDictionary} representing a CCNxInterestReturn.
+ * @return the address of the `CCNxWireFormatMessageInterface` instance that should be used to access the CCNxWireFormatMessage.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketType(schemaVersion, wireFormatBuffer);
+ *
+ * //V1 test
+ * if (ccnxWireFormatMessageInterface_GetInterface(interestReturn) == &CCNxWireFormatFacadeV1_Implementation) {
+ * printf("Using a V1 CCNxWireFormatFacadeV1_Implementation \n");
+ * }
+ *
+ * ...
+ *
+ * ccnxWireFormatMessage_Release(&message);
+ * } * @endcode
+ */
+CCNxWireFormatMessageInterface *ccnxWireFormatMessageInterface_GetInterface(const CCNxTlvDictionary *contentDictionary);
+#endif
diff --git a/libccnx-common/ccnx/common/internal/test/.gitignore b/libccnx-common/ccnx/common/internal/test/.gitignore
new file mode 100644
index 00000000..d8148318
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/.gitignore
@@ -0,0 +1,18 @@
+test_ccnx_ChunkingFacadeV0
+test_ccnx_ChunkingFacadeV1
+test_ccnx_ContentObjectFacadeV0
+test_ccnx_ContentObjectFacadeV1
+test_ccnx_ContentObjectInterface
+test_ccnx_ControlFacade
+test_ccnx_InterestFacadeV0
+test_ccnx_InterestFacadeV1
+test_ccnx_InterestInterface
+test_ccnx_InterestReturnInterface
+test_ccnx_Tlv
+test_ccnx_TlvDictionary
+test_ccnx_TlvEncodingBuffer
+test_ccnx_TlvError
+test_ccnx_ValidationFacadeV0
+test_ccnx_ValidationFacadeV1
+test_ccnx_WireFormatFacadeV0
+test_ccnx_WireFormatFacadeV1
diff --git a/libccnx-common/ccnx/common/internal/test/CMakeLists.txt b/libccnx-common/ccnx/common/internal/test/CMakeLists.txt
new file mode 100644
index 00000000..900ba031
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_ccnx_ChunkingFacadeV1
+ test_ccnx_ContentObjectFacadeV1
+ test_ccnx_ContentObjectInterface
+ test_ccnx_InterestFacadeV1
+ test_ccnx_InterestInterface
+ test_ccnx_InterestReturnFacadeV1
+ test_ccnx_InterestReturnInterface
+ test_ccnx_ManifestFacadeV1
+ test_ccnx_ManifestInterface
+ test_ccnx_TlvDictionary
+ test_ccnx_ValidationFacadeV1
+ test_ccnx_WireFormatFacadeV1
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacade b/libccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacade
new file mode 100755
index 00000000..0894fcbd
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacade
Binary files differ
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacadeV1.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacadeV1.c
new file mode 100755
index 00000000..6f14cf47
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ChunkingFacadeV1.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_ChunkingFacadeV1.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+#include <inttypes.h>
+
+#include <ccnx/common/ccnx_ContentObject.h>
+#include <ccnx/common/ccnx_Interest.h>
+#include <ccnx/common/ccnx_PayloadType.h>
+
+#include <ccnx/common/internal/ccnx_ContentObjectInterface.h>
+
+typedef struct test_data {
+ CCNxName *name;
+ CCNxTlvDictionary *contentObjectV1;
+ CCNxTlvDictionary *contentObjectVFF;
+
+ CCNxTlvDictionary *interest;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->name = ccnxName_CreateFromCString("lci:/foo/bar/v1");
+
+ data->contentObjectV1 =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ data->name,
+ CCNxPayloadType_DATA, NULL);
+
+ data->contentObjectVFF = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+
+ ccnxTlvDictionary_SetMessageType_ContentObject(data->contentObjectVFF, 0xFF);
+
+ data->interest =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ data->name, 5000, NULL, NULL, 100);
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ ccnxName_Release(&data->name);
+ ccnxTlvDictionary_Release(&data->contentObjectV1);
+ ccnxTlvDictionary_Release(&data->contentObjectVFF);
+ ccnxTlvDictionary_Release(&data->interest);
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(ccnx_ChunkingFacade)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_ChunkingFacade)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_ChunkingFacade)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_GetEndChunkNumber_NotContentObject);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_GetEndChunkNumber_V1_With);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_GetEndChunkNumber_V1_Without);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_GetEndChunkNumber_InvalidVersion);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_NotContentObject);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_V1_With);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_V1_Without);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_InvalidVersion);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_SetEndChunkNumber_NotContentObject);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxChunkingFacade_SetEndChunkNumber_InvalidVersion);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ _commonTeardown(data);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ======================================================================================
+
+LONGBOW_TEST_CASE_EXPECTS(Global, ccnxChunkingFacade_GetEndChunkNumber_NotContentObject, .event = &LongBowTrapIllegalValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxChunkingFacadeV1_GetEndChunkNumber(data->interest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxChunkingFacade_GetEndChunkNumber_V1_With)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint64_t endChunkNumber = 5;
+
+ ccnxChunkingFacadeV1_SetEndChunkNumber(data->contentObjectV1, endChunkNumber);
+ uint64_t test = ccnxChunkingFacadeV1_GetEndChunkNumber(data->contentObjectV1);
+ assertTrue(test == endChunkNumber, "wrong value, got %" PRIu64 " expected %" PRIu64 "", test, endChunkNumber)
+ {
+ ccnxTlvDictionary_Display(data->contentObjectV1, 3);
+ }
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, ccnxChunkingFacade_GetEndChunkNumber_V1_Without, .event = &LongBowTrapIllegalValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxChunkingFacadeV1_GetEndChunkNumber(data->contentObjectV1);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, ccnxChunkingFacade_GetEndChunkNumber_InvalidVersion, .event = &LongBowTrapIllegalValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxChunkingFacadeV1_GetEndChunkNumber(data->contentObjectVFF);
+}
+
+// ======================================================================================
+
+
+LONGBOW_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_NotContentObject)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxChunkingFacadeV1_HasEndChunkNumber(data->interest);
+ assertFalse(success, "An Interest should always return FALSE for EndChunkNumber");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_V1_With)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ ccnxChunkingFacadeV1_SetEndChunkNumber(data->contentObjectV1, 5);
+ bool success = ccnxChunkingFacadeV1_HasEndChunkNumber(data->contentObjectV1);
+ assertTrue(success, "Content Object with EndChunkNumber returned false")
+ {
+ ccnxTlvDictionary_Display(data->contentObjectV1, 3);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxChunkingFacade_HasEndChunkNumber_V1_Without)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ bool success = ccnxChunkingFacadeV1_HasEndChunkNumber(data->contentObjectV1);
+ assertFalse(success, "Content Object without EndChunkNumber returned true")
+ {
+ ccnxTlvDictionary_Display(data->contentObjectV1, 3);
+ }
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, ccnxChunkingFacade_HasEndChunkNumber_InvalidVersion, .event = &LongBowTrapIllegalValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxChunkingFacadeV1_HasEndChunkNumber(data->contentObjectVFF);
+}
+
+// ======================================================================================
+
+LONGBOW_TEST_CASE_EXPECTS(Global, ccnxChunkingFacade_SetEndChunkNumber_NotContentObject, .event = &LongBowTrapIllegalValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint64_t endChunkNumber = 7;
+ ccnxChunkingFacadeV1_SetEndChunkNumber(data->interest, endChunkNumber);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxChunkingFacade_SetEndChunkNumber_V1)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint64_t endChunkNumber = 7;
+ bool success = ccnxChunkingFacadeV1_SetEndChunkNumber(data->contentObjectV1, endChunkNumber);
+
+ assertTrue(success, "Setting EndChunkNumber failed")
+ {
+ ccnxTlvDictionary_Display(data->contentObjectV1, 3);
+ }
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, ccnxChunkingFacade_SetEndChunkNumber_InvalidVersion, .event = &LongBowTrapIllegalValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxChunkingFacadeV1_SetEndChunkNumber(data->contentObjectVFF, 7);
+}
+
+// ======================================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ChunkingFacade);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacade b/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacade
new file mode 100755
index 00000000..073ccae4
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacade
Binary files differ
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacadeV1.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacadeV1.c
new file mode 100644
index 00000000..b3c6b343
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectFacadeV1.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_ContentObjectFacadeV1.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+#include <inttypes.h>
+
+typedef struct test_data {
+ CCNxName *name;
+ CCNxPayloadType payloadType;
+ PARCBuffer *payload;
+
+ // a V1 dictionary but with no values set
+ CCNxTlvDictionary *contentObjectV1Empty;
+
+ // a V1 nameless Content Object
+ CCNxTlvDictionary *contentObjectV1Nameless;
+
+ // a valid V1 Content Object
+ CCNxTlvDictionary *contentObjectV1;
+ CCNxTlvDictionary *contentObjectVFF;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->name = ccnxName_CreateFromCString("lci:/foo/bar");
+ data->payloadType = CCNxPayloadType_DATA;
+
+ data->payload = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(20), 7, (uint8_t *) "payload"));
+
+ data->contentObjectV1Empty = ccnxCodecSchemaV1TlvDictionary_CreateContentObject();
+ data->contentObjectV1 = _ccnxContentObjectFacadeV1_CreateWithNameAndPayload(data->name, data->payloadType,
+ data->payload);
+ data->contentObjectV1Nameless = _ccnxContentObjectFacadeV1_CreateWithPayload(data->payloadType, data->payload);
+
+ data->contentObjectVFF = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END);
+ ccnxTlvDictionary_SetMessageType_ContentObject(data->contentObjectVFF, 0xFF);
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ ccnxName_Release(&data->name);
+ parcBuffer_Release(&data->payload);
+
+ ccnxTlvDictionary_Release(&data->contentObjectV1Empty);
+ ccnxTlvDictionary_Release(&data->contentObjectV1);
+ ccnxTlvDictionary_Release(&data->contentObjectV1Nameless);
+ ccnxTlvDictionary_Release(&data->contentObjectVFF);
+ parcMemory_Deallocate((void **) &data);
+}
+
+
+LONGBOW_TEST_RUNNER(ccnx_ContentObjectFacade)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(ImplInterface);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_ContentObjectFacade)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_ContentObjectFacade)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ======================================================================================
+
+LONGBOW_TEST_FIXTURE(ImplInterface)
+{
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_Init);
+
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetName);
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetPayload);
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetPayload);
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetPayload_Link);
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetPayloadType);
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetPayloadType_Unset);
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetExpiryTime);
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetExpiryTime);
+
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetSignature);
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetKeyId);
+
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_ToString);
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_Display);
+ LONGBOW_RUN_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_Equals);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ImplInterface)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ImplInterface)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ======================================================================================
+
+LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_Init)
+{
+ CCNxContentObjectInterface *impl = &CCNxContentObjectFacadeV1_Implementation;
+ assertNotNull(impl->createWithNameAndPayload, "Expected CreateWithNameAndPayload to be set");
+ assertNotNull(impl->createWithPayload, "Expected CreateWithPayload to be set");
+
+ assertNotNull(impl->getName, "Expected GetName to be set");
+ assertNotNull(impl->setSignature, "Expected SetSignature to be set");
+ assertNotNull(impl->getKeyId, "Expected GetKeyID to be set");
+ assertNotNull(impl->getPayload, "Expected GetPayload to be set");
+ assertNotNull(impl->getPayloadType, "Expected GetPayloadType to be set");
+
+ assertNotNull(impl->hasFinalChunkNumber, "Expected HasFinalChunkNumber to be set");
+ assertNotNull(impl->getFinalChunkNumber, "Expected GetFinalChunkNumber to be set");
+ assertNotNull(impl->setFinalChunkNumber, "Expected SetFinalChunkNumber to be set");
+
+ assertNotNull(impl->hasExpiryTime, "Expected HasExpiryTime to be set");
+ assertNotNull(impl->getExpiryTime, "Expected GetExpiryTime to be set");
+ assertNotNull(impl->setExpiryTime, "Expected SetExpiryTime to be set");
+
+ assertNotNull(impl->toString, "Expected ToString to be set");
+ assertNotNull(impl->display, "Expected Display to be set");
+}
+
+LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetName)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxName *test = _ccnxContentObjectFacadeV1_GetName(data->contentObjectV1);
+ assertTrue(ccnxName_Equals(test, data->name), "Names do not match")
+ {
+ ccnxName_Display(test, 0);
+ ccnxName_Display(data->name, 0);
+ }
+ test = _ccnxContentObjectFacadeV1_GetName(data->contentObjectV1Nameless);
+ assertNull(test, "A nameless Content Object has no name.");
+}
+
+LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetPayload)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *newPayload = parcBuffer_WrapCString("this is a new payload");
+
+ // Shouldn't be able to set it on an already initialized ContentObject.
+ // (Though this may change...)
+ assertFalse(_ccnxContentObjectFacadeV1_SetPayload(data->contentObjectV1, CCNxPayloadType_DATA, newPayload),
+ "Expected to not be able to re-assign a payload on an already initialized ContentObject");
+
+ CCNxTlvDictionary *contentObject =
+ _ccnxContentObjectFacadeV1_CreateWithNameAndPayload(data->name,
+ CCNxPayloadType_DATA,
+ NULL);
+
+
+ bool status = _ccnxContentObjectFacadeV1_SetPayload(contentObject, CCNxPayloadType_KEY, newPayload);
+ assertTrue(status, "Expected to be able to set the buffer");
+
+ PARCBuffer *testPayload = _ccnxContentObjectFacadeV1_GetPayload(contentObject);
+ assertTrue(parcBuffer_Equals(newPayload, testPayload), "payloads do not match")
+ {
+ parcBuffer_Display(newPayload, 0);
+ parcBuffer_Display(data->payload, 0);
+ }
+
+ CCNxPayloadType testType = _ccnxContentObjectFacadeV1_GetPayloadType(contentObject);
+ assertTrue(testType == CCNxPayloadType_KEY, "Expected type KEY");
+
+ parcBuffer_Release(&newPayload);
+ ccnxTlvDictionary_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetPayload_Link)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *payload = parcBuffer_WrapCString("this is a payload");
+
+ CCNxTlvDictionary *contentObject =
+ _ccnxContentObjectFacadeV1_CreateWithNameAndPayload(data->name,
+ CCNxPayloadType_LINK,
+ payload);
+
+ PARCBuffer *testPayload = _ccnxContentObjectFacadeV1_GetPayload(contentObject);
+ assertTrue(parcBuffer_Equals(payload, testPayload), "payloads do not match")
+ {
+ parcBuffer_Display(payload, 0);
+ parcBuffer_Display(testPayload, 0);
+ }
+
+ CCNxPayloadType testType = _ccnxContentObjectFacadeV1_GetPayloadType(contentObject);
+ assertTrue(testType == CCNxPayloadType_LINK, "Expected type LINK");
+
+ parcBuffer_Release(&payload);
+ ccnxTlvDictionary_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetPayload)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *test = _ccnxContentObjectFacadeV1_GetPayload(data->contentObjectV1);
+ assertTrue(parcBuffer_Equals(test, data->payload), "payloads do not match")
+ {
+ parcBuffer_Display(test, 0);
+ parcBuffer_Display(data->payload, 0);
+ }
+}
+
+LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetPayloadType)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPayloadType test = _ccnxContentObjectFacadeV1_GetPayloadType(data->contentObjectV1);
+ assertTrue(test == data->payloadType, "payloads do not match, got %d expected %d", test, data->payloadType)
+ {
+ ccnxTlvDictionary_Display(data->contentObjectV1, 0);
+ }
+}
+
+LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetPayloadType_Unset)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPayloadType test = _ccnxContentObjectFacadeV1_GetPayloadType(data->contentObjectV1Empty);
+ assertTrue(test == CCNxPayloadType_DATA, "payloads do not match, got %d expected %d", test, CCNxPayloadType_DATA)
+ {
+ ccnxTlvDictionary_Display(data->contentObjectV1, 0);
+ }
+}
+
+LONGBOW_TEST_CASE_EXPECTS(ImplInterface, ccnxContentObjectFacadeV1_ToString, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ _ccnxContentObjectFacadeV1_ToString(data->contentObjectV1);
+}
+
+LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_Display)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ _ccnxContentObjectFacadeV1_Display(data->contentObjectV1, 0);
+}
+
+LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_Equals)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertTrue(_ccnxContentObjectFacadeV1_Equals(data->contentObjectV1, data->contentObjectV1),
+ "Expected equals to be true");
+ assertFalse(_ccnxContentObjectFacadeV1_Equals(data->contentObjectV1, data->contentObjectV1Empty),
+ "Expected equals to be false");
+}
+
+LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetExpiryTime)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint64_t truth = 12345;
+ ccnxTlvDictionary_PutInteger(data->contentObjectV1, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME, truth);
+
+ assertTrue(_ccnxContentObjectFacadeV1_HasExpiryTime(data->contentObjectV1), "Expected HasExpiryTime() to return true");
+ uint64_t expiryTime = _ccnxContentObjectFacadeV1_GetExpiryTime(data->contentObjectV1);
+ assertTrue(truth == expiryTime, "times do not match, expected %" PRIu64 ", got %" PRIu64, truth, expiryTime);
+}
+
+LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetExpiryTime)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint64_t truth = 12345;
+ _ccnxContentObjectFacadeV1_SetExpiryTime(data->contentObjectV1, truth);
+ uint64_t expiryTime = _ccnxContentObjectFacadeV1_GetExpiryTime(data->contentObjectV1);
+ assertTrue(truth == expiryTime, "times do not match, expected %" PRIu64 ", got %" PRIu64, truth, expiryTime);
+}
+
+LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_SetSignature)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/baz");
+ PARCBuffer *payload = parcBuffer_Allocate(100);
+
+ CCNxTlvDictionary *contentObject = _ccnxContentObjectFacadeV1_CreateWithNameAndPayload(name, CCNxPayloadType_DATA,
+ payload);
+
+ PARCBuffer *keyId = parcBuffer_WrapCString("keyhash");
+ char *rawsig = "siggybits";
+ PARCBuffer *sigbits = parcBuffer_CreateFromArray((void *) rawsig, strlen(rawsig));
+
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, parcBuffer_Flip(sigbits));
+ parcBuffer_Release(&sigbits);
+
+ assertTrue(_ccnxContentObjectFacadeV1_SetSignature(contentObject, keyId, signature, NULL),
+ "Expected to be able to set the signature");
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&payload);
+ parcSignature_Release(&signature);
+ parcBuffer_Release(&keyId);
+ ccnxTlvDictionary_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE(ImplInterface, ccnxContentObjectFacadeV1_GetKeyId)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/baz");
+ PARCBuffer *payload = parcBuffer_Allocate(100);
+
+ CCNxTlvDictionary *contentObject = _ccnxContentObjectFacadeV1_CreateWithNameAndPayload(name, CCNxPayloadType_DATA,
+ payload);
+
+ assertNull(_ccnxContentObjectFacadeV1_GetKeyId(contentObject), "Expect key ID to be NULL");
+
+ PARCBuffer *testKeyId = parcBuffer_WrapCString("keyhash");
+ char *rawsig = "siggybits";
+ PARCBuffer *sigbits = parcBuffer_CreateFromArray((void *) rawsig, strlen(rawsig));
+
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, parcBuffer_Flip(sigbits));
+ parcBuffer_Release(&sigbits);
+
+ assertTrue(_ccnxContentObjectFacadeV1_SetSignature(contentObject, testKeyId, signature, NULL),
+ "Expected to be able to set the signature");
+
+ PARCBuffer *keyId = _ccnxContentObjectFacadeV1_GetKeyId(contentObject);
+
+ assertTrue(parcBuffer_Equals(keyId, testKeyId), "Expect key ID's to be the same");
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&payload);
+ parcSignature_Release(&signature);
+ parcBuffer_Release(&keyId);
+ ccnxTlvDictionary_Release(&contentObject);
+}
+
+// ======================================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ContentObjectFacade);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectInterface.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectInterface.c
new file mode 100755
index 00000000..65e78bed
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ContentObjectInterface.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_ContentObjectInterface.c"
+
+#include <stdio.h>
+
+#include <ccnx/common/ccnx_ContentObject.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(ccnx_ContentObjectInterface)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_ContentObjectInterface)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_ContentObjectInterface)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ======================================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObjectInterface_GetInterface);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ======================================================================================
+
+
+LONGBOW_TEST_CASE(Global, ccnxContentObjectInterface_GetInterface)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+
+ CCNxContentObject *contentObjectV1 =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name,
+ CCNxPayloadType_DATA,
+ NULL);
+
+ assertTrue(ccnxContentObjectInterface_GetInterface(contentObjectV1) == &CCNxContentObjectFacadeV1_Implementation,
+ "Expected V1 Implementation");
+
+ // Now unset the pointer and see if it gets derived properly.
+ ccnxTlvDictionary_SetMessageInterface(contentObjectV1, NULL);
+ assertTrue(ccnxContentObjectInterface_GetInterface(contentObjectV1) == &CCNxContentObjectFacadeV1_Implementation,
+ "Expected V1 Implementation");
+
+
+ ccnxName_Release(&name);
+ ccnxContentObject_Release(&contentObjectV1);
+}
+
+
+// ======================================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ContentObjectInterface);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestFacadeV1.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestFacadeV1.c
new file mode 100755
index 00000000..477b963d
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestFacadeV1.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_InterestFacadeV1.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/ccnx_Interest.h>
+
+typedef struct test_data {
+ CCNxTlvDictionary *interest;
+
+ CCNxName *name;
+ PARCBuffer *keyid;
+ PARCBuffer *contentObjectHash;
+ PARCBuffer *payload;
+
+ // allocated data
+ uint8_t keyidArray[32];
+ uint8_t contentObjectHashArray[32];
+ uint8_t payloadArray[128];
+
+ uint32_t lifetime;
+ uint32_t hoplimit;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->name = ccnxName_CreateFromCString("lci:/once/upon/a/time");
+
+ for (int i = 0; i < 32; i++) {
+ data->keyidArray[i] = i * 7;
+ data->contentObjectHashArray[i] = i * 11;
+ }
+
+ for (int i = 0; i < 128; i++) {
+ data->payloadArray[i] = i * 13;
+ }
+
+ data->keyid = parcBuffer_Wrap(data->keyidArray, 32, 0, 32);
+ data->contentObjectHash = parcBuffer_Wrap(data->contentObjectHashArray, 32, 0, 32);
+ data->payload = parcBuffer_Wrap(data->payloadArray, 128, 0, 128);
+
+ data->lifetime = 900;
+ data->hoplimit = 77;
+
+ data->interest = _ccnxInterestFacadeV1_Create(data->name,
+ data->lifetime,
+ data->keyid,
+ data->contentObjectHash,
+ data->hoplimit);
+
+ _ccnxInterestFacadeV1_SetPayload(data->interest, data->payload);
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ ccnxName_Release(&data->name);
+ parcBuffer_Release(&data->keyid);
+ parcBuffer_Release(&data->contentObjectHash);
+ parcBuffer_Release(&data->payload);
+ ccnxTlvDictionary_Release(&data->interest);
+
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(ccnx_InterestFacadeV1)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_InterestFacadeV1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_InterestFacadeV1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ========================================================================================
+
+LONGBOW_TEST_FIXTURE(Performance)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, newfangled);
+// LONGBOW_RUN_TEST_CASE(Performance, oldtimey);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, newfangled)
+{
+ uint8_t keyidArray[32];
+ for (int i = 0; i < 32; i++) {
+ keyidArray[i] = i;
+ }
+
+ PARCBuffer *keyid = parcBuffer_Wrap(keyidArray, 32, 0, 32);
+ CCNxName *name = ccnxName_CreateFromCString("lci:/dark/and/stormy/bits");
+
+ struct timeval t0, t1;
+ unsigned trials = 10000;
+ gettimeofday(&t0, NULL);
+ for (int i = 0; i < trials; i++) {
+ CCNxTlvDictionary *interest = _ccnxInterestFacadeV1_Create(name,
+ CCNxInterestDefault_LifetimeMilliseconds,
+ keyid,
+ NULL,
+ 0x45);
+
+ ccnxTlvDictionary_Release(&interest);
+ }
+ gettimeofday(&t1, NULL);
+ timersub(&t1, &t0, &t1);
+ double seconds = t1.tv_sec + t1.tv_usec * 1E-6;
+ printf("\nNewFangled iterations %u seconds %.3f msg/sec %.3f\n", trials, seconds, trials / seconds);
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&keyid);
+}
+
+
+// ========================================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_CreateSimple);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_GetContentObjectHash);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_GetHopLimit);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_GetInterestLifetime);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_GetName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_GetPayload);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_GetPublisherPublicKeyDigest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_AssertValid);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_Display);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestFacadeV1_Equals);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_CreateSimple)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *interest = _ccnxInterestFacadeV1_CreateSimple(data->name);
+
+ CCNxName *test = _ccnxInterestFacadeV1_GetName(interest);
+ assertTrue(ccnxName_Equals(test, data->name), "Names do not match");
+ ccnxTlvDictionary_Release(&interest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_GetContentObjectHash)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *test = _ccnxInterestFacadeV1_GetContentObjectHashRestriction(data->interest);
+ assertTrue(parcBuffer_Equals(test, data->contentObjectHash), "ContentObjectHashes do not match")
+ {
+ printf("\ngot : \n"); parcBuffer_Display(test, 3);
+ printf("\nexpected: \n"); parcBuffer_Display(data->contentObjectHash, 3);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_GetHopLimit)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ unsigned test = (unsigned) _ccnxInterestFacadeV1_GetHopLimit(data->interest);
+ assertTrue(test == data->hoplimit, "Wrong hoplimit: got %u expected %u", test, data->hoplimit);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_GetInterestLifetime)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ unsigned test = (unsigned) _ccnxInterestFacadeV1_GetLifetime(data->interest);
+ assertTrue(test == data->lifetime, "Wrong lifetime: got %u expected %u", test, data->lifetime);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_AssertValid)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ _ccnxInterestFacadeV1_Display(data->interest, 4);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_Display)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ _ccnxInterestFacadeV1_AssertValid(data->interest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_GetName)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxName *test = _ccnxInterestFacadeV1_GetName(data->interest);
+ assertTrue(ccnxName_Equals(test, data->name), "Names do not match")
+ {
+ printf("\ngot : \n"); ccnxName_Display(test, 3);
+ printf("\nexpected: \n"); ccnxName_Display(data->name, 3);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_GetPublisherPublicKeyDigest)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *test = _ccnxInterestFacadeV1_GetKeyIdRestriction(data->interest);
+ assertTrue(parcBuffer_Equals(test, data->keyid), "KeyIDs do not match")
+ {
+ printf("\ngot : \n"); parcBuffer_Display(test, 3);
+ printf("\nexpected: \n"); parcBuffer_Display(data->keyid, 3);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_GetPayload)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *test = _ccnxInterestFacadeV1_GetPayload(data->interest);
+ assertTrue(parcBuffer_Equals(test, data->payload), "Payloads do not match")
+ {
+ printf("\ngot : \n"); parcBuffer_Display(test, 3);
+ printf("\nexpected: \n"); parcBuffer_Display(data->payload, 3);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestFacadeV1_Equals)
+{
+ CCNxName *name1 = ccnxName_CreateFromCString("lci:/name/1");
+ CCNxName *name2 = ccnxName_CreateFromCString("lci:/name/2");
+
+ CCNxTlvDictionary *x = _ccnxInterestFacadeV1_CreateSimple(name1); // same
+ CCNxTlvDictionary *y = _ccnxInterestFacadeV1_CreateSimple(name1); // same
+ CCNxTlvDictionary *z = _ccnxInterestFacadeV1_CreateSimple(name1); // same
+
+ CCNxTlvDictionary *diff = _ccnxInterestFacadeV1_CreateSimple(name2); // different
+
+ assertEqualsContract(_ccnxInterestFacadeV1_Equals, x, y, z, diff);
+
+ ccnxTlvDictionary_Release(&x);
+ ccnxTlvDictionary_Release(&y);
+ ccnxTlvDictionary_Release(&z);
+ ccnxTlvDictionary_Release(&diff);
+
+ ccnxName_Release(&name1);
+ ccnxName_Release(&name2);
+}
+
+
+// ========================================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_InterestFacadeV1);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestInterface.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestInterface.c
new file mode 100755
index 00000000..67bde1f5
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestInterface.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+#include <config.h>
+#include <LongBow/unit-test.h>
+
+#include "../ccnx_InterestInterface.c"
+
+#include <stdio.h>
+
+#include <ccnx/common/ccnx_Interest.h>
+#include <ccnx/common/internal/ccnx_InterestDefault.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+
+LONGBOW_TEST_RUNNER(ccnx_InterestInterface)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_InterestInterface)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_InterestInterface)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ======================================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestInterface_GetInterface);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ======================================================================================
+
+
+LONGBOW_TEST_CASE(Global, ccnxInterestInterface_GetInterface)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+
+ CCNxInterest *interestV1 =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name,
+ CCNxInterestDefault_LifetimeMilliseconds,
+ NULL,
+ NULL,
+ CCNxInterestDefault_HopLimit);
+
+ CCNxInterestInterface *interface = ccnxInterestInterface_GetInterface(interestV1);
+ assertTrue(interface == &CCNxInterestFacadeV1_Implementation, "Expected V1 Implementation");
+
+ ccnxName_Release(&name);
+ ccnxInterest_Release(&interestV1);
+}
+
+
+// ======================================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_InterestInterface);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnFacadeV1.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnFacadeV1.c
new file mode 100755
index 00000000..1372a750
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnFacadeV1.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_InterestReturnFacadeV1.c"
+#include "../ccnx_InterestFacadeV1.h"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/ccnx_Interest.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+#include <ccnx/common/ccnx_PayloadType.h>
+
+typedef struct test_data {
+ CCNxTlvDictionary *interest;
+
+ CCNxName *name;
+ PARCBuffer *keyid;
+ PARCBuffer *contentObjectHash;
+ PARCBuffer *payload;
+
+ // allocated data
+ uint8_t keyidArray[32];
+ uint8_t contentObjectHashArray[32];
+ uint8_t payloadArray[128];
+
+ uint32_t lifetime;
+ uint32_t hoplimit;
+ CCNxPayloadType payloadType;
+} TestData;
+
+
+LONGBOW_TEST_RUNNER(ccnx_InterestReturnFacadeV1)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_InterestReturnFacadeV1)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_InterestReturnFacadeV1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ========================================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnFacadeV1_Create);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnFacadeV1_GetReturnCode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%lu) returned NULL", sizeof(TestData));
+ data->name = ccnxName_CreateFromCString("lci:/once/upon/a/time");
+
+ for (int i = 0; i < 32; i++) {
+ data->keyidArray[i] = i * 7;
+ data->contentObjectHashArray[i] = i * 11;
+ }
+
+ for (int i = 0; i < 128; i++) {
+ data->payloadArray[i] = i * 13;
+ }
+
+ data->keyid = parcBuffer_Wrap(data->keyidArray, 32, 0, 32);
+ data->contentObjectHash = parcBuffer_Wrap(data->contentObjectHashArray, 32, 0, 32);
+ data->payloadType = CCNxPayloadType_DATA;
+ data->payload = parcBuffer_Wrap(data->payloadArray, 128, 0, 128);
+
+ data->lifetime = 900;
+ data->hoplimit = 77;
+
+ data->interest = ccnxInterest_Create(data->name,
+ data->lifetime,
+ data->keyid,
+ data->contentObjectHash);
+
+ ccnxInterest_SetPayload(data->interest, data->payload);
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxName_Release(&data->name);
+ parcBuffer_Release(&data->keyid);
+ parcBuffer_Release(&data->contentObjectHash);
+ parcBuffer_Release(&data->payload);
+ ccnxTlvDictionary_Release(&data->interest);
+
+ parcMemory_Deallocate((void **) &data);
+
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_TEARDOWN_FAILED;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestReturnFacadeV1_Create)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxTlvDictionary *interestReturn =
+ _ccnxInterestReturnFacadeV1_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute);
+ assertNotNull(interestReturn, "Expect non-NULL interestReturn");
+ _ccnxInterestReturnFacadeV1_AssertValid(interestReturn);
+
+ CCNxInterestReturn_ReturnCode code = _ccnxInterestReturnFacadeV1_GetReturnCode(interestReturn);
+ assertTrue((CCNxInterestReturn_ReturnCode_NoRoute == code), "InterestReturn wrong Return Code");
+ ccnxTlvDictionary_Release(&interestReturn);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestReturnFacadeV1_GetReturnCode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxTlvDictionary *interestReturn =
+ _ccnxInterestReturnFacadeV1_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute);
+ _ccnxInterestReturnFacadeV1_AssertValid(interestReturn);
+
+ CCNxInterestReturn_ReturnCode code =
+ _ccnxInterestReturnFacadeV1_GetReturnCode(interestReturn);
+
+ assertTrue((CCNxInterestReturn_ReturnCode_NoRoute == code), "InterestReturn wrong Return Code");
+ ccnxTlvDictionary_Release(&interestReturn);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_InterestReturnFacadeV1);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnInterface.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnInterface.c
new file mode 100755
index 00000000..a22ab4e9
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_InterestReturnInterface.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_InterestReturnInterface.c"
+
+#include <ccnx/common/ccnx_InterestReturn.h>
+#include <ccnx/common/internal/ccnx_InterestDefault.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+
+LONGBOW_TEST_RUNNER(ccnx_InterestReturnInterface)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_InterestReturnInterface)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_InterestReturnInterface)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ======================================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnInterface_GetImplementation);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ======================================================================================
+
+
+LONGBOW_TEST_CASE(Global, ccnxInterestReturnInterface_GetImplementation)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+
+ CCNxInterest *interestV1 =
+ ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation,
+ name,
+ CCNxInterestDefault_LifetimeMilliseconds,
+ NULL,
+ NULL,
+ CCNxInterestDefault_HopLimit);
+ ccnxName_Release(&name);
+
+ CCNxInterestReturn *interestReturn = ccnxInterestReturn_Create(interestV1, CCNxInterestReturn_ReturnCode_Congestion);
+
+ assertTrue(ccnxInterestReturnInterface_GetInterface(interestReturn) == &CCNxInterestReturnFacadeV1_Implementation,
+ "Expected V1 Implementation");
+
+ // Now unset the pointer and see if it gets derived properly.
+ ccnxTlvDictionary_SetMessageInterface(interestReturn, NULL);
+
+ assertTrue(ccnxInterestReturnInterface_GetInterface(interestReturn) == &CCNxInterestReturnFacadeV1_Implementation,
+ "Expected V1 Implementation");
+
+ ccnxInterestReturn_Release(&interestReturn);
+ ccnxInterest_Release(&interestV1);
+}
+
+
+// ======================================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_InterestReturnInterface);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ManifestFacadeV1.c.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_ManifestFacadeV1.c.c
new file mode 100644
index 00000000..253b8e5a
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ManifestFacadeV1.c.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_ManifestFacadeV1.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_Memory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/ccnx_Manifest.h>
+
+typedef struct test_data {
+ CCNxTlvDictionary *manifest;
+
+ CCNxName *name;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->name = ccnxName_CreateFromCString("lci:/once/upon/a/time");
+ data->manifest = _ccnxManifestFacadeV1_Create(data->name);
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ ccnxName_Release(&data->name);
+ ccnxTlvDictionary_Release(&data->manifest);
+
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(ccnx_ManifestFacadeV1)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_ManifestFacadeV1)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_ManifestFacadeV1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ========================================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestFacadeV1_Create);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestFacadeV1_GetName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestFacadeV1_AddHashGroup);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestFacadeV1_GetHashGroup);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestFacadeV1_Equals);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestFacadeV1_Create)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *manifest = _ccnxManifestFacadeV1_Create(data->name);
+
+ const CCNxName *test = _ccnxManifestFacadeV1_GetName(manifest);
+ assertTrue(ccnxName_Equals(test, data->name), "Names do not match");
+ ccnxTlvDictionary_Release(&manifest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestFacadeV1_AddHashGroup)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *manifest = _ccnxManifestFacadeV1_Create(data->name);
+
+ int actual = 0;
+ int numberOfGroups = _ccnxManifestFacadeV1_GetNumberOfHashGroups(manifest);
+ assertTrue(numberOfGroups == actual, "Expected %d, got %d", actual, numberOfGroups);
+
+ CCNxManifestHashGroup *hashGroup = ccnxManifestHashGroup_Create();
+ _ccnxManifestFacadeV1_AddHashGroup(manifest, hashGroup);
+ actual++;
+ numberOfGroups = _ccnxManifestFacadeV1_GetNumberOfHashGroups(manifest);
+
+ assertTrue(numberOfGroups == actual, "Expected %d, got %d", actual, numberOfGroups);
+
+ ccnxManifestHashGroup_Release(&hashGroup);
+ ccnxTlvDictionary_Release(&manifest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestFacadeV1_GetHashGroup)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *manifest = _ccnxManifestFacadeV1_Create(data->name);
+
+ CCNxManifestHashGroup *hashGroup = ccnxManifestHashGroup_Create();
+ _ccnxManifestFacadeV1_AddHashGroup(manifest, hashGroup);
+
+ CCNxManifestHashGroup *firstGroup = _ccnxManifestFacadeV1_GetHashGroup(manifest, 0);
+ assertTrue(ccnxManifestHashGroup_Equals(hashGroup, firstGroup), "Expected the HashGroups to be equal");
+
+ ccnxManifestHashGroup_Release(&hashGroup);
+ ccnxManifestHashGroup_Release(&firstGroup);
+ ccnxTlvDictionary_Release(&manifest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestFacadeV1_GetNumberOfHashGroups)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *manifest = _ccnxManifestFacadeV1_Create(data->name);
+
+ size_t numberOfGroups = _ccnxManifestFacadeV1_GetNumberOfHashGroups(manifest);
+ assertTrue(numberOfGroups == 1, "Expected 1 group, got %zu", numberOfGroups);
+ ccnxTlvDictionary_Release(&manifest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestFacadeV1_GetName)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ const CCNxName *test = _ccnxManifestFacadeV1_GetName(data->manifest);
+ assertTrue(ccnxName_Equals(test, data->name), "Names do not match")
+ {
+ printf("\ngot : \n"); ccnxName_Display(test, 3);
+ printf("\nexpected: \n"); ccnxName_Display(data->name, 3);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestFacadeV1_Equals)
+{
+ CCNxName *name1 = ccnxName_CreateFromCString("lci:/name/1");
+ CCNxName *name2 = ccnxName_CreateFromCString("lci:/name/2");
+
+ CCNxTlvDictionary *x = _ccnxManifestFacadeV1_Create(name1);
+ CCNxTlvDictionary *y = _ccnxManifestFacadeV1_Create(name1);
+ CCNxTlvDictionary *z = _ccnxManifestFacadeV1_Create(name1);
+
+ CCNxTlvDictionary *diff = _ccnxManifestFacadeV1_Create(name2);
+
+ assertEqualsContract(_ccnxManifestFacadeV1_Equals, x, y, z, diff, NULL);
+
+ ccnxTlvDictionary_Release(&x);
+ ccnxTlvDictionary_Release(&y);
+ ccnxTlvDictionary_Release(&z);
+ ccnxTlvDictionary_Release(&diff);
+
+ ccnxName_Release(&name1);
+ ccnxName_Release(&name2);
+}
+
+// ========================================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ManifestFacadeV1);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ManifestInterface.c.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_ManifestInterface.c.c
new file mode 100755
index 00000000..42ce095f
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ManifestInterface.c.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_ManifestInterface.c"
+
+#include <ccnx/common/ccnx_Manifest.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+
+LONGBOW_TEST_RUNNER(ccnx_ManifestInterface)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_ManifestInterface)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_ManifestInterface)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ======================================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestInterface_GetImplementation);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ======================================================================================
+
+
+LONGBOW_TEST_CASE(Global, ccnxManifestInterface_GetImplementation)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+
+ CCNxManifest *manifestV1 = ccnxManifest_Create(name);
+ ccnxName_Release(&name);
+
+ assertTrue(ccnxManifestInterface_GetInterface(manifestV1) == &CCNxManifestFacadeV1_Interface, "Expected V1 Implementation");
+
+ // Now unset the pointer and see if it gets derived properly.
+ ccnxTlvDictionary_SetMessageInterface(manifestV1, NULL);
+
+ assertTrue(ccnxManifestInterface_GetInterface(manifestV1) == &CCNxManifestFacadeV1_Interface, "Expected V1 Implementation");
+
+ ccnxManifest_Release(&manifestV1);
+}
+
+
+// ======================================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ManifestInterface);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_TlvDictionary.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_TlvDictionary.c
new file mode 100755
index 00000000..51936d96
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_TlvDictionary.c
@@ -0,0 +1,1142 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_TlvDictionary.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <ccnx/common/internal/ccnx_ContentObjectInterface.h>
+#include <ccnx/common/internal/ccnx_InterestInterface.h>
+
+#include <LongBow/unit-test.h>
+
+typedef struct test_data {
+ CCNxTlvDictionary *dictionary;
+ size_t fastArraySize;
+ size_t listSize;
+} TestData;
+
+typedef enum {
+ SchemaFree = 0,
+ SchemaBuffer = 1,
+ SchemaInteger = 2,
+ SchemaIoVec = 3,
+ SchemaJson = 4,
+ SchemaName = 5,
+ SchemaEnd = 6,
+} TestSchema;
+
+static CCNxCodecNetworkBufferIoVec *
+createIoVec(void)
+{
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+ return vec;
+}
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->fastArraySize = SchemaEnd + 2;
+ data->listSize = SchemaEnd + 10;
+ data->dictionary = ccnxTlvDictionary_Create(data->fastArraySize, data->listSize);
+
+ // populate the know test vectors
+ PARCBuffer *buffer = parcBuffer_Allocate(5);
+ ccnxTlvDictionary_PutBuffer(data->dictionary, SchemaBuffer, buffer);
+ parcBuffer_Release(&buffer);
+
+ ccnxTlvDictionary_PutInteger(data->dictionary, SchemaInteger, 42);
+
+ CCNxCodecNetworkBufferIoVec *vec = createIoVec();
+ ccnxTlvDictionary_PutIoVec(data->dictionary, SchemaIoVec, vec);
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+
+ PARCJSON *json = parcJSON_ParseString("{\"KEY\": \"VALUE\"}");
+ ccnxTlvDictionary_PutJson(data->dictionary, SchemaJson, json);
+ parcJSON_Release(&json);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/great/gatsby");
+ ccnxTlvDictionary_PutName(data->dictionary, SchemaName, name);
+ ccnxName_Release(&name);
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ ccnxTlvDictionary_Release(&data->dictionary);
+ parcMemory_Deallocate((void **) &data);
+}
+
+// =============================================================
+
+LONGBOW_TEST_RUNNER(rta_TlvDictionary)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(KnownKeys);
+ LONGBOW_RUN_TEST_FIXTURE(UnknownKeys);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+
+ // type specific tests
+ LONGBOW_RUN_TEST_FIXTURE(Buffer);
+ LONGBOW_RUN_TEST_FIXTURE(Integer);
+ LONGBOW_RUN_TEST_FIXTURE(IoVec);
+ LONGBOW_RUN_TEST_FIXTURE(Json);
+ LONGBOW_RUN_TEST_FIXTURE(Name);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(rta_TlvDictionary)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_TlvDictionary)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// =============================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_Performance);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_Create);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_Release);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_ContentObject);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_Interest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_Control);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_InterestReturn);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_SetGetMessageTypeImplementation);
+
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTlvDictionary_ShallowCopy);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_Performance)
+{
+ int reps = 100000;
+ struct timeval t0, t1;
+ gettimeofday(&t0, NULL);
+ for (int i = 0; i < reps; i++) {
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(10, 20);
+ ccnxTlvDictionary_Release(&dictionary);
+ }
+ gettimeofday(&t1, NULL);
+ timersub(&t1, &t0, &t1);
+ double seconds = t1.tv_sec + t1.tv_usec * 1E-6;
+
+ printf("time %.6f seconds, tps = %.2f\n", seconds, (double) reps / seconds);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_Acquire)
+{
+ CCNxTlvDictionary *first = ccnxTlvDictionary_Create(10, 20);
+ CCNxTlvDictionary *second = ccnxTlvDictionary_Acquire(first);
+
+ assertTrue(parcObject_GetReferenceCount(first) == 2, "Wrong ref count, got %" PRIu64 " expected %u", parcObject_GetReferenceCount(first), 2);
+
+ ccnxTlvDictionary_Release(&second);
+ ccnxTlvDictionary_Release(&first);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_Create)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(20, 30);
+ assertNotNull(dictionary, "Got null dictionary from Create");
+ assertNotNull(dictionary->directArray, "DirectArray is null");
+ assertNotNull(dictionary->fixedListHeads, "fixedListHeads is null");
+
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_Release)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(1, 1);
+ ccnxTlvDictionary_Release(&dictionary);
+ assertNull(dictionary, "Release did not null argument");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_ContentObject)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(1, 1);
+ ccnxTlvDictionary_SetMessageType_ContentObject(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ assertTrue(ccnxTlvDictionary_IsContentObject(dictionary), "Wrong message type");
+ assertFalse(ccnxTlvDictionary_IsControl(dictionary), "Wrong message type");
+ assertFalse(ccnxTlvDictionary_IsInterest(dictionary), "Wrong message type");
+ assertFalse(ccnxTlvDictionary_IsInterestReturn(dictionary), "Wrong message type");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(dictionary) == CCNxTlvDictionary_SchemaVersion_V1, "Wrong schema type");
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_Interest)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(1, 1);
+ ccnxTlvDictionary_SetMessageType_Interest(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ assertFalse(ccnxTlvDictionary_IsContentObject(dictionary), "Wrong message type");
+ assertFalse(ccnxTlvDictionary_IsControl(dictionary), "Wrong message type");
+ assertTrue(ccnxTlvDictionary_IsInterest(dictionary), "Wrong message type");
+ assertFalse(ccnxTlvDictionary_IsInterestReturn(dictionary), "Wrong message type");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(dictionary) == CCNxTlvDictionary_SchemaVersion_V1, "Wrong schema type");
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_Control)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(1, 1);
+ ccnxTlvDictionary_SetMessageType_Control(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ assertFalse(ccnxTlvDictionary_IsContentObject(dictionary), "Wrong message type");
+ assertTrue(ccnxTlvDictionary_IsControl(dictionary), "Wrong message type");
+ assertFalse(ccnxTlvDictionary_IsInterest(dictionary), "Wrong message type");
+ assertFalse(ccnxTlvDictionary_IsInterestReturn(dictionary), "Wrong message type");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(dictionary) == CCNxTlvDictionary_SchemaVersion_V1, "Wrong schema type");
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_SetMessageType_InterestReturn)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(1, 1);
+ ccnxTlvDictionary_SetMessageType_InterestReturn(dictionary, CCNxTlvDictionary_SchemaVersion_V1);
+ assertFalse(ccnxTlvDictionary_IsContentObject(dictionary), "Wrong message type");
+ assertFalse(ccnxTlvDictionary_IsControl(dictionary), "Wrong message type");
+ assertFalse(ccnxTlvDictionary_IsInterest(dictionary), "Wrong message type");
+ assertTrue(ccnxTlvDictionary_IsInterestReturn(dictionary), "Wrong message type");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(dictionary) == CCNxTlvDictionary_SchemaVersion_V1, "Wrong schema type");
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_SetGetMessageTypeImplementation)
+{
+ CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(1, 1);
+ void *impl = ccnxTlvDictionary_GetMessageInterface(dictionary);
+
+ assertNull(impl, "Expected a NULL implementation by default");
+
+ ccnxTlvDictionary_SetMessageInterface(dictionary, &CCNxContentObjectFacadeV1_Implementation);
+ assertTrue(ccnxTlvDictionary_GetMessageInterface(dictionary) == &CCNxContentObjectFacadeV1_Implementation,
+ "Expected CCNxContentObjectFacadeV1_Implementation");
+
+ ccnxTlvDictionary_SetMessageInterface(dictionary, &CCNxContentObjectFacadeV1_Implementation);
+ assertTrue(ccnxTlvDictionary_GetMessageInterface(dictionary) == &CCNxContentObjectFacadeV1_Implementation,
+ "Expected CCNxContentObjectFacadeV1_Implementation");
+
+ ccnxTlvDictionary_SetMessageInterface(dictionary, &CCNxInterestFacadeV1_Implementation);
+ assertTrue(ccnxTlvDictionary_GetMessageInterface(dictionary) == &CCNxInterestFacadeV1_Implementation,
+ "Expected CCNxInterestFacadeV1_Implementation");
+
+ ccnxTlvDictionary_SetMessageInterface(dictionary, &CCNxInterestFacadeV1_Implementation);
+ assertTrue(ccnxTlvDictionary_GetMessageInterface(dictionary) == &CCNxInterestFacadeV1_Implementation,
+ "Expected CCNxInterestFacadeV1_Implementation");
+
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_Equals)
+{
+ CCNxTlvDictionary *a = ccnxTlvDictionary_Create(1, 1);
+ CCNxTlvDictionary *b = ccnxTlvDictionary_Create(1, 1);
+ CCNxTlvDictionary *c = ccnxTlvDictionary_Create(1, 1);
+
+ ccnxTlvDictionary_SetMessageType_Interest(a, CCNxTlvDictionary_SchemaVersion_V1);
+ ccnxTlvDictionary_SetMessageType_Interest(b, CCNxTlvDictionary_SchemaVersion_V1);
+ ccnxTlvDictionary_SetMessageType_Interest(c, CCNxTlvDictionary_SchemaVersion_V1);
+
+ CCNxTlvDictionary *diffArraySize = ccnxTlvDictionary_Create(2, 1);
+ CCNxTlvDictionary *diffListSize = ccnxTlvDictionary_Create(1, 2);
+ CCNxTlvDictionary *diffType = ccnxTlvDictionary_Create(1, 1);
+ ccnxTlvDictionary_SetMessageType_Control(diffType, CCNxTlvDictionary_SchemaVersion_V1);
+
+ CCNxTlvDictionary *diffType2 = ccnxTlvDictionary_Create(1, 1);
+ ccnxTlvDictionary_SetMessageType_ContentObject(diffType2, CCNxTlvDictionary_SchemaVersion_V1);
+
+ assertEqualsContract(ccnxTlvDictionary_Equals, a, b, c, diffArraySize, diffListSize, diffType, diffType2, NULL);
+
+ ccnxTlvDictionary_Release(&diffType2);
+ ccnxTlvDictionary_Release(&diffType);
+ ccnxTlvDictionary_Release(&diffListSize);
+ ccnxTlvDictionary_Release(&diffArraySize);
+ ccnxTlvDictionary_Release(&c);
+ ccnxTlvDictionary_Release(&b);
+ ccnxTlvDictionary_Release(&a);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTlvDictionary_ShallowCopy)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxTlvDictionary *a = data->dictionary;
+
+ PARCBuffer *buffer = parcBuffer_WrapCString("Some Stuff");
+ ccnxTlvDictionary_PutListBuffer(a, SchemaEnd, 23, buffer);
+ parcBuffer_Release(&buffer);
+
+ CCNxTlvDictionary *b = ccnxTlvDictionary_ShallowCopy(a);
+
+ assertTrue(ccnxTlvDictionary_Equals(a, b), "Expected Dictionaries to be Equal after ShallowCopy");
+
+ ccnxTlvDictionary_Release(&b);
+}
+
+// ================================================================
+
+LONGBOW_TEST_FIXTURE(KnownKeys)
+{
+ LONGBOW_RUN_TEST_CASE(KnownKeys, ccnxTlvDictionary_Get_Exists);
+ LONGBOW_RUN_TEST_CASE(KnownKeys, ccnxTlvDictionary_Get_NotExists);
+ LONGBOW_RUN_TEST_CASE(KnownKeys, ccnxTlvDictionary_Put_Unique);
+ LONGBOW_RUN_TEST_CASE(KnownKeys, ccnxTlvDictionary_Put_Duplicate);
+
+ LONGBOW_RUN_TEST_CASE(KnownKeys, ccnxTlvDictionary_PutList_Unique);
+ LONGBOW_RUN_TEST_CASE(KnownKeys, ccnxTlvDictionary_PutList_Duplicate);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(KnownKeys)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(KnownKeys)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(KnownKeys, ccnxTlvDictionary_Get_Exists)
+{
+ uint32_t key = SchemaEnd;
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+
+ ccnxTlvDictionary_PutBuffer(data->dictionary, key, buffer);
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(data->dictionary, key);
+ assertTrue(test == buffer, "Get value wrong, got %p expected %p", (void *) test, (void *) buffer);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(KnownKeys, ccnxTlvDictionary_Get_NotExists)
+{
+ uint32_t key = SchemaEnd;
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ ccnxTlvDictionary_PutBuffer(data->dictionary, key, buffer);
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(data->dictionary, key + 1);
+ assertNull(test, "Get for missing key should return null");
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(KnownKeys, ccnxTlvDictionary_Put_Unique)
+{
+ uint32_t key = SchemaEnd;
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ bool success = ccnxTlvDictionary_PutBuffer(data->dictionary, key, buffer);
+ assertTrue(success, "Put returned false adding a unique key");
+ parcBuffer_Release(&buffer);
+
+ // one extra test particular to it being in the fast array
+ assertTrue(data->dictionary->directArray[key].entryType == ENTRY_BUFFER, "Not buffer type, got %d", data->dictionary->directArray[key].entryType);
+ assertNotNull(data->dictionary->directArray[key]._entry.buffer, "They fast array entry for key is null");
+}
+
+LONGBOW_TEST_CASE(KnownKeys, ccnxTlvDictionary_Put_Duplicate)
+{
+ uint32_t key = SchemaEnd;
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ ccnxTlvDictionary_PutBuffer(data->dictionary, key, buffer);
+ bool success = ccnxTlvDictionary_PutBuffer(data->dictionary, key, buffer);
+ assertFalse(success, "Put returned true adding a duplicate key");
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(KnownKeys, ccnxTlvDictionary_PutList_Unique)
+{
+ uint32_t listKey = SchemaEnd;
+ uint32_t bufferKey = 1000;
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ bool success = ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, bufferKey, buffer);
+ assertTrue(success, "Put returned false adding a unique key");
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(KnownKeys, ccnxTlvDictionary_PutList_Duplicate)
+{
+ uint32_t listKey = SchemaEnd;
+ uint32_t bufferKey = 1000;
+
+ // its ok to have duplicates of the custom keys
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, bufferKey, buffer);
+ bool success = ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, bufferKey, buffer);
+ assertTrue(success, "Put returned false adding a duplicate key to list");
+ parcBuffer_Release(&buffer);
+}
+
+// ================================================================
+
+LONGBOW_TEST_FIXTURE(UnknownKeys)
+{
+ LONGBOW_RUN_TEST_CASE(UnknownKeys, ccnxTlvDictionary_PutList_Unique);
+ LONGBOW_RUN_TEST_CASE(UnknownKeys, ccnxTlvDictionary_PutList_Duplicate);
+
+ LONGBOW_RUN_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListGetByPosition);
+ LONGBOW_RUN_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListGetByType);
+ LONGBOW_RUN_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListSize);
+ LONGBOW_RUN_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListEquals);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(UnknownKeys)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownKeys)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(UnknownKeys, ccnxTlvDictionary_PutList_Unique)
+{
+ uint32_t listKey = FIXED_LIST_LENGTH + 1;
+ uint32_t bufferKey = 1000;
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ bool success = ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, bufferKey, buffer);
+ assertTrue(success, "Put returned false adding a unique key");
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(UnknownKeys, ccnxTlvDictionary_PutList_Duplicate)
+{
+ uint32_t listKey = FIXED_LIST_LENGTH + 1;
+ uint32_t bufferKey = 1000;
+
+ // its ok to have duplicates of the custom keys
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, bufferKey, buffer);
+ bool success = ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, bufferKey, buffer);
+ assertTrue(success, "Put returned false adding a duplicate key to list");
+ parcBuffer_Release(&buffer);
+}
+
+/*
+ * Add 3 items to list then make sure we can retrieve the 2nd
+ */
+LONGBOW_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListGetByPosition)
+{
+ uint32_t listKey = SchemaEnd;
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *a = parcBuffer_Allocate(1);
+ PARCBuffer *b = parcBuffer_Allocate(1);
+ PARCBuffer *c = parcBuffer_Allocate(1);
+
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1000, a);
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1001, b);
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1002, c);
+
+ PARCBuffer *test = NULL;
+ uint32_t testkey = 0;
+ ccnxTlvDictionary_ListGetByPosition(data->dictionary, listKey, 1, &test, &testkey);
+
+ assertTrue(testkey == 1001, "Wrong key, expected %u got %u", 1001, testkey);
+ assertTrue(test == b, "Wrong buffer, expected %p got %p", (void *) b, (void *) test);
+
+ parcBuffer_Release(&a);
+ parcBuffer_Release(&b);
+ parcBuffer_Release(&c);
+}
+
+/*
+ * Add 3 items to list then make sure we can retrieve the 2nd
+ */
+LONGBOW_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListGetByType)
+{
+ uint32_t listKey = SchemaEnd;
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *a = parcBuffer_Allocate(1);
+ PARCBuffer *b = parcBuffer_Allocate(1);
+ PARCBuffer *c = parcBuffer_Allocate(1);
+
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1000, a);
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1001, b);
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1002, c);
+
+ PARCBuffer *test = ccnxTlvDictionary_ListGetByType(data->dictionary, listKey, 1001);
+ assertTrue(test == b, "Wrong buffer, expected %p got %p", (void *) b, (void *) test);
+
+ parcBuffer_Release(&a);
+ parcBuffer_Release(&b);
+ parcBuffer_Release(&c);
+}
+
+LONGBOW_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListSize)
+{
+ uint32_t listKey = SchemaEnd;
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *a = parcBuffer_Allocate(1);
+ PARCBuffer *b = parcBuffer_Allocate(1);
+ PARCBuffer *c = parcBuffer_Allocate(1);
+
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1000, a);
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1001, b);
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, listKey, 1002, c);
+
+ size_t length = ccnxTlvDictionary_ListSize(data->dictionary, listKey);
+ assertTrue(length == 3, "Wrong length, expected %u got %zu", 3, length);
+
+ parcBuffer_Release(&a);
+ parcBuffer_Release(&b);
+ parcBuffer_Release(&c);
+}
+
+LONGBOW_TEST_CASE(UnknownKeys, ccnxTlvDictionary_ListEquals)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *a = parcBuffer_Allocate(1);
+ PARCBuffer *b = parcBuffer_Allocate(1);
+ PARCBuffer *c = parcBuffer_Allocate(1);
+
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, 6, 1000, a);
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, 6, 1001, b);
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, 6, 1002, c);
+
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, 7, 1000, a);
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, 7, 1001, b);
+ ccnxTlvDictionary_PutListBuffer(data->dictionary, 7, 1002, c);
+
+ bool equals = _ccnxTlvDictionary_ListEquals(_getListHead(data->dictionary, 6), _getListHead(data->dictionary, 7));
+ assertTrue(equals, "Lists should be equal");
+
+ parcBuffer_Release(&a);
+ parcBuffer_Release(&b);
+ parcBuffer_Release(&c);
+}
+
+
+
+// =============================================================
+
+LONGBOW_TEST_FIXTURE(Buffer)
+{
+ LONGBOW_RUN_TEST_CASE(Buffer, ccnxTlvDictionary_GetBuffer_Exists);
+ LONGBOW_RUN_TEST_CASE(Buffer, ccnxTlvDictionary_GetBuffer_Missing);
+ LONGBOW_RUN_TEST_CASE(Buffer, ccnxTlvDictionary_PutBuffer_OK);
+ LONGBOW_RUN_TEST_CASE(Buffer, ccnxTlvDictionary_PutBuffer_Duplicate);
+ LONGBOW_RUN_TEST_CASE(Buffer, ccnxTlvDictionary_IsValueBuffer_True);
+ LONGBOW_RUN_TEST_CASE(Buffer, ccnxTlvDictionary_IsValueBuffer_False);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Buffer)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Buffer)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Buffer, ccnxTlvDictionary_GetBuffer_Exists)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(data->dictionary, SchemaBuffer);
+ assertNotNull(test, "Got null buffer from key that hsould be buffer");
+}
+
+LONGBOW_TEST_CASE(Buffer, ccnxTlvDictionary_GetBuffer_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxTlvDictionary_GetBuffer(data->dictionary, SchemaFree);
+}
+
+LONGBOW_TEST_CASE(Buffer, ccnxTlvDictionary_PutBuffer_OK)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ bool success = ccnxTlvDictionary_PutBuffer(data->dictionary, SchemaFree, buffer);
+ assertTrue(success, "Did not put buffer in to available slot");
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Buffer, ccnxTlvDictionary_PutBuffer_Duplicate)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ bool success = ccnxTlvDictionary_PutBuffer(data->dictionary, SchemaBuffer, buffer);
+ assertFalse(success, "Should have failed putting duplicate");
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Buffer, ccnxTlvDictionary_IsValueBuffer_True)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxTlvDictionary_IsValueBuffer(data->dictionary, SchemaBuffer);
+ assertTrue(success, "Should have succeeded on a buffer key");
+}
+
+LONGBOW_TEST_CASE(Buffer, ccnxTlvDictionary_IsValueBuffer_False)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxTlvDictionary_IsValueBuffer(data->dictionary, SchemaInteger);
+ assertFalse(success, "Should have failed on a non-buffer");
+}
+
+// =============================================================
+
+LONGBOW_TEST_FIXTURE(Integer)
+{
+ LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_GetInteger_Exists);
+ LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_GetInteger_Missing);
+ LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_PutInteger_OK);
+ LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_PutInteger_Duplicate);
+ LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_PutInteger_OverBuffer);
+ LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_IsValueInteger_True);
+ LONGBOW_RUN_TEST_CASE(Integer, ccnxTlvDictionary_IsValueInteger_False);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Integer)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Integer)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Integer, ccnxTlvDictionary_GetInteger_Exists)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint64_t test = ccnxTlvDictionary_GetInteger(data->dictionary, SchemaInteger);
+ assertTrue(test == 42, "Got wrong integer, got %" PRIu64 " expected 42", test);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Integer, ccnxTlvDictionary_GetInteger_Missing, .event = &LongBowTrapIllegalValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxTlvDictionary_GetInteger(data->dictionary, SchemaBuffer);
+}
+
+LONGBOW_TEST_CASE(Integer, ccnxTlvDictionary_PutInteger_OK)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxTlvDictionary_PutInteger(data->dictionary, SchemaFree, 69);
+ assertTrue(success, "Did not put integer in to available slot");
+}
+
+LONGBOW_TEST_CASE(Integer, ccnxTlvDictionary_PutInteger_Duplicate)
+{
+ // we allow replacing integer
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxTlvDictionary_PutInteger(data->dictionary, SchemaInteger, 69);
+ assertTrue(success, "Should have succeeded putting duplicate");
+}
+
+LONGBOW_TEST_CASE(Integer, ccnxTlvDictionary_PutInteger_OverBuffer)
+{
+ // This will fail, cannot change a buffer to an integer
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxTlvDictionary_PutInteger(data->dictionary, SchemaBuffer, 69);
+ assertFalse(success, "Should not be able to change a buffer to an integer");
+}
+
+LONGBOW_TEST_CASE(Integer, ccnxTlvDictionary_IsValueInteger_True)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxTlvDictionary_IsValueInteger(data->dictionary, SchemaInteger);
+ assertTrue(success, "Should have succeeded on a integer key");
+}
+
+LONGBOW_TEST_CASE(Integer, ccnxTlvDictionary_IsValueInteger_False)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxTlvDictionary_IsValueInteger(data->dictionary, SchemaBuffer);
+ assertFalse(success, "Should have failed on a non-integer");
+}
+
+// =============================================================
+
+LONGBOW_TEST_FIXTURE(IoVec)
+{
+ LONGBOW_RUN_TEST_CASE(IoVec, ccnxTlvDictionary_GetIoVec_Exists);
+ LONGBOW_RUN_TEST_CASE(IoVec, ccnxTlvDictionary_GetIoVec_Missing);
+ LONGBOW_RUN_TEST_CASE(IoVec, ccnxTlvDictionary_PutIoVec_OK);
+ LONGBOW_RUN_TEST_CASE(IoVec, ccnxTlvDictionary_PutIoVec_Duplicate);
+ LONGBOW_RUN_TEST_CASE(IoVec, ccnxTlvDictionary_IsValueIoVec_True);
+ LONGBOW_RUN_TEST_CASE(IoVec, ccnxTlvDictionary_IsValueIoVec_False);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(IoVec)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(IoVec)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(IoVec, ccnxTlvDictionary_GetIoVec_Exists)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxCodecNetworkBufferIoVec *test = ccnxTlvDictionary_GetIoVec(data->dictionary, SchemaIoVec);
+ assertNotNull(test, "Got null buffer from key that hsould be buffer");
+}
+
+LONGBOW_TEST_CASE(IoVec, ccnxTlvDictionary_GetIoVec_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxTlvDictionary_GetIoVec(data->dictionary, SchemaFree);
+}
+
+LONGBOW_TEST_CASE(IoVec, ccnxTlvDictionary_PutIoVec_OK)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxCodecNetworkBufferIoVec *vec = createIoVec();
+ bool success = ccnxTlvDictionary_PutIoVec(data->dictionary, SchemaFree, vec);
+ assertTrue(success, "Did not put vec in to available slot");
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+LONGBOW_TEST_CASE(IoVec, ccnxTlvDictionary_PutIoVec_Duplicate)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxCodecNetworkBufferIoVec *vec = createIoVec();
+ bool success = ccnxTlvDictionary_PutIoVec(data->dictionary, SchemaIoVec, vec);
+ assertFalse(success, "Should have failed putting duplicate");
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+LONGBOW_TEST_CASE(IoVec, ccnxTlvDictionary_IsValueIoVec_True)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxTlvDictionary_IsValueIoVec(data->dictionary, SchemaIoVec);
+ assertTrue(success, "Should have succeeded on a vec key");
+}
+
+LONGBOW_TEST_CASE(IoVec, ccnxTlvDictionary_IsValueIoVec_False)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxTlvDictionary_IsValueIoVec(data->dictionary, SchemaInteger);
+ assertFalse(success, "Should have failed on a non-vec");
+}
+
+// =============================================================
+
+LONGBOW_TEST_FIXTURE(Json)
+{
+ LONGBOW_RUN_TEST_CASE(Json, ccnxTlvDictionary_GetJson_Exists);
+ LONGBOW_RUN_TEST_CASE(Json, ccnxTlvDictionary_GetJson_Missing);
+ LONGBOW_RUN_TEST_CASE(Json, ccnxTlvDictionary_PutJson_OK);
+ LONGBOW_RUN_TEST_CASE(Json, ccnxTlvDictionary_PutJson_Duplicate);
+ LONGBOW_RUN_TEST_CASE(Json, ccnxTlvDictionary_IsValueJson_True);
+ LONGBOW_RUN_TEST_CASE(Json, ccnxTlvDictionary_IsValueJson_False);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Json)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Json)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Json, ccnxTlvDictionary_GetJson_Exists)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCJSON *test = ccnxTlvDictionary_GetJson(data->dictionary, SchemaJson);
+ assertNotNull(test, "Got null json from key that should be json");
+}
+
+LONGBOW_TEST_CASE(Json, ccnxTlvDictionary_GetJson_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCJSON *test = ccnxTlvDictionary_GetJson(data->dictionary, SchemaFree);
+ assertNull(test, "Should have gotten null for non-json key");
+}
+
+LONGBOW_TEST_CASE(Json, ccnxTlvDictionary_PutJson_OK)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCJSON *json = parcJSON_Create();
+ bool success = ccnxTlvDictionary_PutJson(data->dictionary, SchemaFree, json);
+ assertTrue(success, "Did not put buffer in to available slot");
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(Json, ccnxTlvDictionary_PutJson_Duplicate)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCJSON *json = parcJSON_Create();
+ bool success = ccnxTlvDictionary_PutJson(data->dictionary, SchemaJson, json);
+ assertFalse(success, "Should have failed putting duplicate");
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(Json, ccnxTlvDictionary_IsValueJson_True)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxTlvDictionary_IsValueJson(data->dictionary, SchemaJson);
+ assertTrue(success, "Should have succeeded on a json key");
+}
+
+LONGBOW_TEST_CASE(Json, ccnxTlvDictionary_IsValueJson_False)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxTlvDictionary_IsValueJson(data->dictionary, SchemaInteger);
+ assertFalse(success, "Should have failed on a non-json");
+}
+
+// =============================================================
+
+LONGBOW_TEST_FIXTURE(Name)
+{
+ LONGBOW_RUN_TEST_CASE(Name, ccnxTlvDictionary_GetName_Exists);
+ LONGBOW_RUN_TEST_CASE(Name, ccnxTlvDictionary_GetName_Missing);
+ LONGBOW_RUN_TEST_CASE(Name, ccnxTlvDictionary_PutName_OK);
+ LONGBOW_RUN_TEST_CASE(Name, ccnxTlvDictionary_PutName_Duplicate);
+ LONGBOW_RUN_TEST_CASE(Name, ccnxTlvDictionary_IsValueName_True);
+ LONGBOW_RUN_TEST_CASE(Name, ccnxTlvDictionary_IsValueName_False);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Name)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Name)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Name, ccnxTlvDictionary_GetName_Exists)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxName *test = ccnxTlvDictionary_GetName(data->dictionary, SchemaName);
+ assertNotNull(test, "Got null json from key that should be name");
+}
+
+LONGBOW_TEST_CASE(Name, ccnxTlvDictionary_GetName_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxName *test = ccnxTlvDictionary_GetName(data->dictionary, SchemaFree);
+ assertNull(test, "Should have gotten null for non-name key");
+}
+
+LONGBOW_TEST_CASE(Name, ccnxTlvDictionary_PutName_OK)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxName *name = ccnxName_Create();
+ bool success = ccnxTlvDictionary_PutName(data->dictionary, SchemaFree, name);
+ assertTrue(success, "Did not put name in to available slot");
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Name, ccnxTlvDictionary_PutName_Duplicate)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxName *name = ccnxName_Create();
+ bool success = ccnxTlvDictionary_PutName(data->dictionary, SchemaName, name);
+ assertFalse(success, "Should have failed putting duplicate");
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Name, ccnxTlvDictionary_IsValueName_True)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxTlvDictionary_IsValueName(data->dictionary, SchemaName);
+ assertTrue(success, "Should have succeeded on a json key");
+}
+
+LONGBOW_TEST_CASE(Name, ccnxTlvDictionary_IsValueName_False)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success = ccnxTlvDictionary_IsValueName(data->dictionary, SchemaInteger);
+ assertFalse(success, "Should have failed on a non-json");
+}
+
+// =============================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTlvEntry_Equals_Unset);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTlvEntry_Equals_Buffer);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTlvEntry_Equals_Integer);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTlvEntry_Equals_IoVec);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTlvEntry_Equals_Json);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTlvEntry_Equals_Name);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void
+assertRtaTlvEntryEquals(int length, _CCNxTlvDictionaryEntry array[length])
+{
+ assertTrue(length == 5, "Must provide 5 array elements");
+ assertEqualsContract((bool (*)(void *, void *))_ccnxTlvDictionaryEntry_Equals, &array[0], &array[1], &array[2], &array[3], &array[4], NULL);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTlvEntry_Equals_Unset)
+{
+ _CCNxTlvDictionaryEntry array[5];
+ memset(&array, 0, sizeof(array));
+
+ array[3].entryType = ENTRY_JSON;
+ array[4].entryType = ENTRY_BUFFER;
+ assertRtaTlvEntryEquals(5, array);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTlvEntry_Equals_Buffer)
+{
+ char apple[] = "apple";
+ char bananna[] = "bannana";
+
+ _CCNxTlvDictionaryEntry array[5];
+ memset(&array, 0, sizeof(array));
+
+ for (int i = 0; i < 3; i++) {
+ array[i].entryType = ENTRY_BUFFER;
+ array[i]._entry.buffer = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(20), sizeof(apple), (uint8_t *) apple));
+ }
+
+ array[3].entryType = ENTRY_JSON;
+ array[4].entryType = ENTRY_BUFFER;
+ array[4]._entry.buffer = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(20), sizeof(bananna), (uint8_t *) bananna));
+ assertRtaTlvEntryEquals(5, array);
+
+ for (int i = 0; i < 5; i++) {
+ if (array[i]._entry.buffer) {
+ parcBuffer_Release(&array[i]._entry.buffer);
+ }
+ }
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTlvEntry_Equals_Integer)
+{
+ _CCNxTlvDictionaryEntry array[5];
+ memset(&array, 0, sizeof(array));
+
+ for (int i = 0; i < 3; i++) {
+ array[i].entryType = ENTRY_INTEGER;
+ array[i]._entry.integer = 13;
+ }
+
+ array[3].entryType = ENTRY_JSON;
+ array[4].entryType = ENTRY_INTEGER;
+ array[4]._entry.integer = 99;
+
+ assertRtaTlvEntryEquals(5, array);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTlvEntry_Equals_IoVec)
+{
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&ParcMemoryMemoryBlock, NULL);
+ ccnxCodecNetworkBuffer_PutUint8(netbuff, 0);
+ CCNxCodecNetworkBufferIoVec *unequal = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+
+ _CCNxTlvDictionaryEntry array[5];
+ memset(&array, 0, sizeof(array));
+
+ for (int i = 0; i < 3; i++) {
+ array[i].entryType = ENTRY_IOVEC;
+ array[i]._entry.vec = createIoVec();
+ }
+
+ array[3].entryType = ENTRY_JSON;
+ array[4].entryType = ENTRY_IOVEC;
+ array[4]._entry.vec = unequal;
+ assertRtaTlvEntryEquals(5, array);
+
+ for (int i = 0; i < 5; i++) {
+ if (array[i]._entry.vec) {
+ ccnxCodecNetworkBufferIoVec_Release(&array[i]._entry.vec);
+ }
+ }
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTlvEntry_Equals_Json)
+{
+ char apple[] = "{\"apple\": 0}";
+ char bananna[] = "{\"bannana\": 1}";
+
+ _CCNxTlvDictionaryEntry array[5];
+ memset(&array, 0, sizeof(array));
+
+ for (int i = 0; i < 3; i++) {
+ array[i].entryType = ENTRY_JSON;
+ array[i]._entry.json = parcJSON_ParseString(apple);
+ }
+
+ array[3].entryType = ENTRY_JSON;
+ array[4].entryType = ENTRY_JSON;
+ array[4]._entry.json = parcJSON_ParseString(bananna);
+ assertRtaTlvEntryEquals(5, array);
+
+ for (int i = 0; i < 5; i++) {
+ if (array[i]._entry.json) {
+ parcJSON_Release(&array[i]._entry.json);
+ }
+ }
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTlvEntry_Equals_Name)
+{
+ char apple[] = "lci:/apple";
+ char bananna[] = "lci:/bannana";
+
+ _CCNxTlvDictionaryEntry array[5];
+ memset(&array, 0, sizeof(array));
+
+ for (int i = 0; i < 3; i++) {
+ array[i].entryType = ENTRY_NAME;
+ array[i]._entry.name = ccnxName_CreateFromCString(apple);
+ }
+
+ array[3].entryType = ENTRY_JSON;
+ array[4].entryType = ENTRY_NAME;
+ array[4]._entry.name = ccnxName_CreateFromCString(bananna);
+ assertRtaTlvEntryEquals(5, array);
+
+ for (int i = 0; i < 5; i++) {
+ if (array[i]._entry.name) {
+ ccnxName_Release(&array[i]._entry.name);
+ }
+ }
+}
+
+// =============================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_TlvDictionary);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacade b/libccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacade
new file mode 100755
index 00000000..39a27830
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacade
Binary files differ
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacadeV1.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacadeV1.c
new file mode 100755
index 00000000..fe3ead29
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_ValidationFacadeV1.c
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Setter tests use ground truth by examining the dictionary.
+ * Getter tests use the setters to set values.
+ *
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_ValidationFacadeV1.c"
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+//#include "../validation/test/testrig_validation.c"
+
+LONGBOW_TEST_RUNNER(ccnx_ValidationFacadeV1)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Setters);
+ LONGBOW_RUN_TEST_FIXTURE(Getters);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_ValidationFacadeV1)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_ValidationFacadeV1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Setters)
+{
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetKeyId);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetKeyName);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetPublicKey);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetCertificate);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetPayload);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetCryptoSuite);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_SetSigningTime);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Setters)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Setters)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_SetKeyId)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ PARCBuffer *keyid = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5);
+ bool success = ccnxValidationFacadeV1_SetKeyId(dictionary, keyid);
+ assertTrue(success, "Failed to set keyid");
+
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID);
+ assertTrue(parcBuffer_Equals(test, keyid), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(keyid, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&keyid);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_SetKeyName)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ PARCBuffer *keyid = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5);
+ PARCBuffer *hash = parcBuffer_Wrap((uint8_t []) { 11, 12, 13, 14 }, 4, 0, 4);
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo");
+ CCNxLink *link = ccnxLink_Create(name, keyid, hash);
+
+ bool success = ccnxValidationFacadeV1_SetKeyName(dictionary, link);
+ assertTrue(success, "Failed to set keyname");
+
+ CCNxName *testName = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME);
+ assertTrue(ccnxName_Equals(testName, name), "Wrong name")
+ {
+ printf("Expected\n");
+ ccnxName_Display(name, 3);
+ printf("Got\n");
+ ccnxName_Display(testName, 3);
+ }
+
+ PARCBuffer *testKeyid = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID);
+ assertTrue(parcBuffer_Equals(testKeyid, keyid), "Wrong keyid")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(keyid, 3);
+ printf("Got\n");
+ parcBuffer_Display(testKeyid, 3);
+ }
+
+ PARCBuffer *testHash = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH);
+ assertTrue(parcBuffer_Equals(testHash, hash), "Wrong hash")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(hash, 3);
+ printf("Got\n");
+ parcBuffer_Display(testHash, 3);
+ }
+
+ parcBuffer_Release(&hash);
+ parcBuffer_Release(&keyid);
+ ccnxName_Release(&name);
+ ccnxLink_Release(&link);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_SetPublicKey)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ PARCBuffer *key = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5);
+ bool success = ccnxValidationFacadeV1_SetPublicKey(dictionary, key);
+ assertTrue(success, "Failed to set keyid");
+
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY);
+ assertTrue(parcBuffer_Equals(test, key), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(key, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&key);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_SetCertificate)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ PARCBuffer *cert = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5);
+ bool success = ccnxValidationFacadeV1_SetCertificate(dictionary, cert);
+ assertTrue(success, "Failed to set keyid");
+
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT);
+ assertTrue(parcBuffer_Equals(test, cert), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(cert, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&cert);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_SetPayload)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ PARCBuffer *payload = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5);
+ bool success = ccnxValidationFacadeV1_SetPayload(dictionary, payload);
+ assertTrue(success, "Failed to set keyid");
+
+ PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD);
+ assertTrue(parcBuffer_Equals(test, payload), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(payload, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&payload);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_SetCryptoSuite)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256;
+ bool success = ccnxValidationFacadeV1_SetCryptoSuite(dictionary, suite);
+ assertTrue(success, "Failed to set keyid");
+
+ bool hasCryptoSuite = ccnxTlvDictionary_IsValueInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ assertTrue(hasCryptoSuite, "Dictionary does not have a crypto suite value in it");
+
+ PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ assertTrue(test == suite, "Wrong suite, expected %d got %d", suite, test);
+
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_SetSigningTime)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ uint64_t signingTime = 0x0102030405060708ULL;
+
+ bool success = ccnxValidationFacadeV1_SetSigningTime(dictionary, signingTime);
+ assertTrue(success, "Failed to set signing time");
+
+ bool hasSigningTime = ccnxTlvDictionary_IsValueInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME);
+ assertTrue(hasSigningTime, "Dictionary does not have a signing time value in it");
+
+ uint64_t test = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME);
+ assertTrue(test == signingTime, "Wrong signing time, expected %" PRIx64 " got %" PRIx64, signingTime, test);
+
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+// =============================================================
+
+LONGBOW_TEST_FIXTURE(Getters)
+{
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetKeyId);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetKeyName);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetPublicKey);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetCertificate);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetPayload);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_HasCryptoSuite_True);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_HasCryptoSuite_False);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetCryptoSuite);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_HasSigningTime_True);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_HasSigningTime_False);
+ LONGBOW_RUN_TEST_CASE(Setters, ccnxValidationFacadeV1_GetSigningTime);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Getters)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Getters)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_GetKeyId)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ PARCBuffer *keyid = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5);
+ ccnxValidationFacadeV1_SetKeyId(dictionary, keyid);
+
+ PARCBuffer *test = ccnxValidationFacadeV1_GetKeyId(dictionary);
+ assertTrue(parcBuffer_Equals(test, keyid), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(keyid, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&keyid);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_GetKeyName)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ PARCBuffer *keyid = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5);
+ PARCBuffer *hash = parcBuffer_Wrap((uint8_t []) { 11, 12, 13, 14 }, 4, 0, 4);
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo");
+ CCNxLink *link = ccnxLink_Create(name, keyid, hash);
+
+ ccnxValidationFacadeV1_SetKeyName(dictionary, link);
+
+ CCNxLink *testLink = ccnxValidationFacadeV1_GetKeyName(dictionary);
+ assertTrue(ccnxLink_Equals(testLink, link), "Wrong link");
+ // no ccnxLink_Dispay, so cannot easily display items
+
+ ccnxLink_Release(&testLink);
+ parcBuffer_Release(&hash);
+ parcBuffer_Release(&keyid);
+ ccnxName_Release(&name);
+ ccnxLink_Release(&link);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_GetPublicKey)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ PARCBuffer *key = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5);
+ ccnxValidationFacadeV1_SetPublicKey(dictionary, key);
+
+ PARCBuffer *test = ccnxValidationFacadeV1_GetPublicKey(dictionary);
+ assertTrue(parcBuffer_Equals(test, key), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(key, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&key);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_GetCertificate)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ PARCBuffer *cert = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5);
+ ccnxValidationFacadeV1_SetCertificate(dictionary, cert);
+
+ PARCBuffer *test = ccnxValidationFacadeV1_GetCertificate(dictionary);
+ assertTrue(parcBuffer_Equals(test, cert), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(cert, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&cert);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_GetPayload)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ PARCBuffer *payload = parcBuffer_Wrap((uint8_t []) { 1, 2, 3, 4, 5 }, 5, 0, 5);
+ ccnxValidationFacadeV1_SetPayload(dictionary, payload);
+
+ PARCBuffer *test = ccnxValidationFacadeV1_GetPayload(dictionary);
+ assertTrue(parcBuffer_Equals(test, payload), "Buffer mismatch")
+ {
+ printf("Expected\n");
+ parcBuffer_Display(payload, 3);
+ printf("Got\n");
+ parcBuffer_Display(test, 3);
+ }
+
+ parcBuffer_Release(&payload);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_HasCryptoSuite_True)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256;
+ ccnxValidationFacadeV1_SetCryptoSuite(dictionary, suite);
+
+ bool hasCryptoSuite = ccnxValidationFacadeV1_HasCryptoSuite(dictionary);
+ assertTrue(hasCryptoSuite, "Dictionary does not have a crypto suite value in it");
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_HasCryptoSuite_False)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ bool hasCryptoSuite = ccnxValidationFacadeV1_HasCryptoSuite(dictionary);
+ assertFalse(hasCryptoSuite, "Dictionary says it has a crypto suite when none was set");
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_GetCryptoSuite)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256;
+ ccnxValidationFacadeV1_SetCryptoSuite(dictionary, suite);
+
+ PARCCryptoSuite test = ccnxValidationFacadeV1_GetCryptoSuite(dictionary);
+ assertTrue(test == suite, "Wrong crypto suite, expected %d got %d", suite, test);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_HasSigningTime_True)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ uint64_t signingTime = 0x0102030405060708ULL;
+ ccnxValidationFacadeV1_SetSigningTime(dictionary, signingTime);
+
+ bool hasSigningTime = ccnxValidationFacadeV1_HasSigningTime(dictionary);
+ assertTrue(hasSigningTime, "Dictionary does not have a signing time value in it");
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_HasSigningTime_False)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+
+ bool hasSigningTime = ccnxValidationFacadeV1_HasSigningTime(dictionary);
+ assertFalse(hasSigningTime, "Dictionary says it has a signing time when none was set");
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Setters, ccnxValidationFacadeV1_GetSigningTime)
+{
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ uint64_t signingTime = 0x0102030405060708ULL;
+ ccnxValidationFacadeV1_SetSigningTime(dictionary, signingTime);
+
+ uint64_t test = ccnxValidationFacadeV1_GetSigningTime(dictionary);
+ assertTrue(test == signingTime, "Wrong signing time, expected %" PRIx64 " got %" PRIx64, signingTime, test);
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+
+// =============================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ValidationFacadeV1);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/internal/test/test_ccnx_WireFormatFacadeV1.c b/libccnx-common/ccnx/common/internal/test/test_ccnx_WireFormatFacadeV1.c
new file mode 100755
index 00000000..194ef02c
--- /dev/null
+++ b/libccnx-common/ccnx/common/internal/test/test_ccnx_WireFormatFacadeV1.c
@@ -0,0 +1,594 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_WireFormatFacadeV1.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/ccnx_ContentObject.h>
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+#include <ccnx/common/codec/ccnxCodec_TlvPacket.h>
+
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h>
+
+LONGBOW_TEST_RUNNER(ccnx_WireFormatFacade)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(SchemaV1);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_WireFormatFacade)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_WireFormatFacade)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/*
+ * Small size allocator for creating a network buffer
+ */
+static size_t
+allocator(void *userarg, size_t bytes, void **output)
+{
+ const size_t allocationSize = *(size_t *) userarg;
+ void *allocated = parcMemory_Allocate(allocationSize);
+ *output = allocated;
+ return allocationSize;
+}
+
+/*
+ * deallocator for network buffer
+ */
+static void
+deallocator(void *userarg, void **memoryPtr)
+{
+ parcMemory_Deallocate(memoryPtr);
+}
+
+static const CCNxCodecNetworkBufferMemoryBlockFunctions memory = { .allocator = allocator, .deallocator = deallocator };
+
+/*
+ * Create a network buffer that looks like this. The actual number of iovecs might
+ * be a little different, but the digest area will span several iovec.
+ *
+ * +-----------+-----------+-----------+-----------+-----------+
+ * iov[0] iov[1] iov[2] iov[3]
+ * +-----------+-----------+-----------+-----------+-----------+
+ * ^ ^
+ * | |
+ * start end
+ */
+static CCNxCodecNetworkBufferIoVec *
+createNetworkBufferIoVec(size_t allocationSize, size_t padlen, uint8_t pad[padlen], size_t datalen, uint8_t data[datalen])
+{
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&memory, &allocationSize);
+ // build the network buffer
+ ccnxCodecNetworkBuffer_PutArray(netbuff, padlen, pad);
+ ccnxCodecNetworkBuffer_PutArray(netbuff, datalen, data);
+ ccnxCodecNetworkBuffer_PutArray(netbuff, padlen, pad);
+
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+ return vec;
+}
+
+// =======================================================================
+
+LONGBOW_TEST_FIXTURE(SchemaV1)
+{
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromContentObjectPacketType);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromControlPacketType);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromInterestPacketType);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromInterestReturnPacketType);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Get);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Put);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_WriteToFile);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromInterestPacketTypeIoVec);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_GetIoVec);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_SetHopLimit);
+
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_SetProtectedRegionStart);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_SetProtectedRegionLength);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_HashProtectedRegion_Buffer);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_HashProtectedRegion_IoVec);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_ComputeContentObjectHash);
+
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_Interest);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_ContentObject);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_Control);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_InterestReturn);
+ LONGBOW_RUN_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_UnknownPacketType);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(SchemaV1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(SchemaV1)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromContentObjectPacketType)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromContentObjectPacketType(buffer);
+ assertNotNull(wireformat, "Got null wireformat");
+ assertTrue(ccnxTlvDictionary_IsContentObject(wireformat), "Wrong message type");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(wireformat) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema, got %d expected %d",
+ ccnxTlvDictionary_GetSchemaVersion(wireformat), CCNxTlvDictionary_SchemaVersion_V1);
+
+ ccnxTlvDictionary_Release(&wireformat);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromControlPacketType)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromControlPacketType(buffer);
+ assertNotNull(wireformat, "Got null wireformat");
+ assertTrue(ccnxTlvDictionary_IsControl(wireformat), "Wrong message type");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(wireformat) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema, got %d expected %d",
+ ccnxTlvDictionary_GetSchemaVersion(wireformat), CCNxTlvDictionary_SchemaVersion_V1);
+
+ ccnxTlvDictionary_Release(&wireformat);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromInterestPacketType)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromInterestPacketType(buffer);
+ assertNotNull(wireformat, "Got null wireformat");
+ assertTrue(ccnxTlvDictionary_IsInterest(wireformat), "Wrong message type");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(wireformat) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema, got %d expected %d",
+ ccnxTlvDictionary_GetSchemaVersion(wireformat), CCNxTlvDictionary_SchemaVersion_V1);
+
+ ccnxTlvDictionary_Release(&wireformat);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromInterestReturnPacketType)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromInterestReturnPacketType(buffer);
+ assertNotNull(wireformat, "Got null wireformat");
+ assertTrue(ccnxTlvDictionary_IsInterestReturn(wireformat), "Wrong message type");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(wireformat) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema, got %d expected %d",
+ ccnxTlvDictionary_GetSchemaVersion(wireformat), CCNxTlvDictionary_SchemaVersion_V1);
+
+ ccnxTlvDictionary_Release(&wireformat);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Get)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromInterestPacketType(buffer);
+
+ PARCBuffer *test = _ccnxWireFormatFacadeV1_GetWireFormatBuffer(wireformat);
+ assertTrue(test == buffer, "Wrong iovec: got %p expected %p", (void *) test, (void *) buffer);
+
+ ccnxTlvDictionary_Release(&wireformat);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Put)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ CCNxTlvDictionary *packet = ccnxTlvDictionary_Create(20, 20);
+ ccnxTlvDictionary_SetMessageType_Interest(packet, CCNxTlvDictionary_SchemaVersion_V1);
+ bool success = _ccnxWireFormatFacadeV1_PutWireFormatBuffer(packet, buffer);
+
+ assertTrue(success, "Failed to put buffer in to dictionary");
+
+ ccnxTlvDictionary_Release(&packet);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_WriteToFile)
+{
+ const char string[] = "Hello dev null\n";
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string));
+ CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromInterestPacketType(buffer);
+
+ _ccnxWireFormatFacadeV1_WriteToFile(wireformat, "/dev/null");
+
+ ccnxTlvDictionary_Release(&wireformat);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_FromInterestPacketTypeIoVec)
+{
+ uint8_t data[64];
+
+ uint8_t pad[32];
+ CCNxCodecNetworkBufferIoVec *vec = createNetworkBufferIoVec(512, 32, pad, 64, data);
+
+ CCNxTlvDictionary *wireformat = _ccnxWireFormatFacadeV1_FromInterestPacketTypeIoVec(vec);
+ assertNotNull(wireformat, "Got null wireformat");
+ assertTrue(ccnxTlvDictionary_IsInterest(wireformat), "Wrong message type");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(wireformat) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema, got %d expected %d",
+ ccnxTlvDictionary_GetSchemaVersion(wireformat), CCNxTlvDictionary_SchemaVersion_V1);
+
+ ccnxTlvDictionary_Release(&wireformat);
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_GetIoVec)
+{
+ uint8_t *data = parcMemory_Allocate(64);
+ memset(data, 0, 64);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, 64, data);
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+
+ CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ _ccnxWireFormatFacadeV1_PutIoVec(packet, iovec);
+
+ CCNxCodecNetworkBufferIoVec *test = _ccnxWireFormatFacadeV1_GetIoVec(packet);
+ assertTrue(test == iovec, "Failed to get iovec from dictionary, expected %p got %p", (void *) iovec, (void *) test);
+
+ ccnxTlvDictionary_Release(&packet);
+ parcBuffer_Release(&buffer);
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_SetHopLimit)
+{
+ uint8_t *data = parcMemory_Allocate(64);
+ memset(data, 0, 64);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, 64, data);
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+
+ CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ _ccnxWireFormatFacadeV1_PutIoVec(packet, iovec);
+
+ _ccnxWireFormatFacadeV1_SetHopLimit(packet, 10);
+
+ ccnxTlvDictionary_Release(&packet);
+ parcBuffer_Release(&buffer);
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+
+ CCNxCodecSchemaV1InterestHeader header;
+
+ buffer = parcBuffer_Wrap((void *) &header, sizeof(header), 0, sizeof(header));
+
+ packet = _ccnxWireFormatFacadeV1_FromContentObjectPacketType(buffer);
+
+ _ccnxWireFormatFacadeV1_SetHopLimit(packet, 10);
+
+ ccnxTlvDictionary_Release(&packet);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_SetProtectedRegionStart)
+{
+ const char string[] = "Hello dev null\n";
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string));
+
+ CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ _ccnxWireFormatFacadeV1_PutWireFormatBuffer(packet, buffer);
+
+ size_t start = 5;
+ bool success = _ccnxWireFormatFacadeV1_SetProtectedRegionStart(packet, start);
+ assertTrue(success, "Failed to put integer in to dictionary");
+
+ assertTrue(ccnxTlvDictionary_IsValueInteger(packet, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedStart), "ProtectedStart not set");
+
+ ccnxTlvDictionary_Release(&packet);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_SetProtectedRegionLength)
+{
+ const char string[] = "Hello dev null\n";
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string));
+
+ CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ _ccnxWireFormatFacadeV1_PutWireFormatBuffer(packet, buffer);
+
+ size_t length = 5;
+ bool success = _ccnxWireFormatFacadeV1_SetProtectedRegionLength(packet, length);
+ assertTrue(success, "Failed to put integer in to dictionary");
+
+ assertTrue(ccnxTlvDictionary_IsValueInteger(packet, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedLength), "ProtectedLength not set");
+
+ ccnxTlvDictionary_Release(&packet);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_HashProtectedRegion_Buffer)
+{
+ // >1234<
+ const char string[] = "Hello dev null\n";
+
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string));
+ size_t start = 5;
+ size_t length = 4;
+
+ CCNxTlvDictionary *packet = _ccnxWireFormatFacadeV1_FromContentObjectPacketType(buffer);
+ _ccnxWireFormatFacadeV1_SetProtectedRegionStart(packet, start);
+ _ccnxWireFormatFacadeV1_SetProtectedRegionLength(packet, length);
+
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ PARCCryptoHash *hash = _ccnxWireFormatFacadeV1_HashProtectedRegion(packet, hasher);
+
+ // the correctness of the has is tested in _ccnxWireFormatFacadeV1_ComputeHash
+ assertNotNull(hash, "Got null hash from a good packet");
+
+ ccnxTlvDictionary_Release(&packet);
+ parcCryptoHash_Release(&hash);
+ parcBuffer_Release(&buffer);
+ parcCryptoHasher_Release(&hasher);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_HashProtectedRegion_IoVec)
+{
+ uint8_t *data = parcMemory_Allocate(64);
+ memset(data, 0, 64);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, 64, data);
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+
+ CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ _ccnxWireFormatFacadeV1_PutIoVec(packet, iovec);
+
+ _ccnxWireFormatFacadeV1_SetProtectedRegionStart(packet, 0);
+ _ccnxWireFormatFacadeV1_SetProtectedRegionLength(packet, 64);
+
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ PARCCryptoHash *hash = _ccnxWireFormatFacadeV1_HashProtectedRegion(packet, hasher);
+
+ // the correctness of the has is tested in _ccnxWireFormatFacadeV1_ComputeHash
+ assertNotNull(hash, "Got null hash from a good packet");
+
+ ccnxTlvDictionary_Release(&packet);
+ parcCryptoHash_Release(&hash);
+ parcBuffer_Release(&buffer);
+ parcCryptoHasher_Release(&hasher);
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_Interest)
+{
+ PARCBuffer *wireFormat = parcBuffer_Wrap(v1_interest_nameA, sizeof(v1_interest_nameA), 0, sizeof(v1_interest_nameA));
+ CCNxTlvDictionary *test = _ccnxWireFormatFacadeV1_CreateFromV1(wireFormat);
+ assertNotNull(test, "Got null dictionary for good interest");
+ assertTrue(ccnxTlvDictionary_IsInterest(test), "Dictionary says it is not an Interest");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == 1, "Schema says it is not v1");
+ parcBuffer_Release(&wireFormat);
+ ccnxTlvDictionary_Release(&test);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_ContentObject)
+{
+ PARCBuffer *wireFormat = parcBuffer_Wrap(v1_content_nameA_crc32c, sizeof(v1_content_nameA_crc32c), 0, sizeof(v1_content_nameA_crc32c));
+ CCNxTlvDictionary *test = _ccnxWireFormatFacadeV1_CreateFromV1(wireFormat);
+ assertNotNull(test, "Got null dictionary for good content object");
+ assertTrue(ccnxTlvDictionary_IsContentObject(test), "Dictionary says it is not a Content Object");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == 1, "Schema says it is not v1");
+ parcBuffer_Release(&wireFormat);
+ ccnxTlvDictionary_Release(&test);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_Control)
+{
+ PARCBuffer *wireFormat = parcBuffer_Wrap(v1_cpi_add_route, sizeof(v1_cpi_add_route), 0, sizeof(v1_cpi_add_route));
+ CCNxTlvDictionary *test = _ccnxWireFormatFacadeV1_CreateFromV1(wireFormat);
+ assertNotNull(test, "Got null dictionary for good control");
+ assertTrue(ccnxTlvDictionary_IsControl(test), "Dictionary says it is not a control");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == 1, "Schema says it is not v1");
+ parcBuffer_Release(&wireFormat);
+ ccnxTlvDictionary_Release(&test);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_InterestReturn)
+{
+ uint8_t encoded[] = { 1, CCNxCodecSchemaV1Types_PacketType_InterestReturn, 0, 23 };
+ PARCBuffer *wireFormat = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxTlvDictionary *test = _ccnxWireFormatFacadeV1_CreateFromV1(wireFormat);
+ assertNotNull(test, "Got null dictionary for good InterestReturn");
+ assertTrue(ccnxTlvDictionary_IsInterestReturn(test), "Expected IsInterestReturn() to be true");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == 1, "Schema says it is not v1");
+ parcBuffer_Release(&wireFormat);
+ ccnxTlvDictionary_Release(&test);
+}
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_Create_UnknownPacketType)
+{
+ uint8_t encoded[] = { 1, 99, 0, 23 };
+ PARCBuffer *wireFormat = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded));
+ CCNxTlvDictionary *test = _ccnxWireFormatFacadeV1_CreateFromV1(wireFormat);
+ assertNull(test, "Should have gotten null dictionary for unknown packet type");
+ parcBuffer_Release(&wireFormat);
+}
+
+
+static uint8_t _v1_ContentObject_WithKnownHash[] = {
+ // Name: lci:/boose/roo/pie
+ // Payload: "this is the payload"
+ // Signer: CRC32
+ // CO Hash: 4FB301EA5FD523B9A71287B721DC20C94B2D4827674A8CA275B7D57C60447876
+
+ 0x01, 0x01, 0x00, 0x4e, // Fixed Header
+ 0x00, 0x00, 0x00, 0x08,
+
+ 0x00, 0x02, 0x00, 0x32, // Type 2 == ContentObject, length 50 (0x32)
+ 0x00, 0x00, 0x00, 0x17, // Name, length 23 (0x17)
+
+ 0x00, 0x01, 0x00, 0x05, // NameSegment, length 5
+ 0x62, 0x6f, 0x6f, 0x73, // "boose"
+ 0x65,
+
+ 0x00, 0x01, 0x00, 0x03, // NameSegment, length 3
+ 0x72, 0x6f, 0x6f, // "roo"
+
+ 0x00, 0x01, 0x00, 0x03, // NameSegment, length 3
+ 0x70, 0x69, 0x65, // "pie"
+
+ 0x00, 0x01, 0x00, 0x13, // Payload, length 19 (0x13)
+ 0x74, 0x68, 0x69, 0x73, // "this is the payload"
+ 0x20, 0x69, 0x73, 0x20,
+ 0x74, 0x68, 0x65, 0x20,
+ 0x70, 0x61, 0x79, 0x6c,
+ 0x6f, 0x61, 0x64,
+
+ 0x00, 0x03, 0x00, 0x04, // Validation Alg, length 4
+ 0x00, 0x02, 0x00, 0x00, // CRC32, length 0
+
+ 0x00, 0x04, 0x00, 0x04, // Validation Payload, length 4
+ 0x7e, 0x60, 0x54, 0xc4, // The payload (the CRC32)
+};
+
+LONGBOW_TEST_CASE(SchemaV1, ccnxWireFormatFacadeV1_ComputeContentObjectHash)
+{
+ PARCBuffer *wireFormatBuffer = parcBuffer_Wrap(_v1_ContentObject_WithKnownHash, sizeof(_v1_ContentObject_WithKnownHash),
+ 0, sizeof(_v1_ContentObject_WithKnownHash));
+
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_Create(wireFormatBuffer);
+
+ CCNxTlvDictionary *contentObject = ccnxWireFormatMessage_GetDictionary(message);
+
+ // We have a partially unpacked dictionary now, but we need to more fully unpack it for our processing.
+ assertTrue(ccnxCodecTlvPacket_BufferDecode(wireFormatBuffer, contentObject), "Expected to decode the wireformat buffer");
+
+
+ PARCCryptoHash *coHash = _ccnxWireFormatFacadeV1_ComputeContentObjectHash(contentObject);
+
+ assertNotNull(coHash, "Expected a non-NULL content object hash");
+
+ char *computedHash = parcBuffer_ToHexString(parcCryptoHash_GetDigest(coHash));
+
+ char *knownHash = "4FB301EA5FD523B9A71287B721DC20C94B2D4827674A8CA275B7D57C60447876";
+
+ assertTrue(strncasecmp(computedHash, knownHash, strlen(knownHash)) == 0, "Expected a matching ContentObject hash");
+
+ parcMemory_Deallocate(&computedHash);
+ parcCryptoHash_Release(&coHash);
+ parcBuffer_Release(&wireFormatBuffer);
+
+ ccnxContentObject_Release(&contentObject);
+}
+
+// =======================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _ccnxWireFormatFacadeV1_ComputeHash);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_CASE(Local, _ccnxWireFormatFacadeV1_ComputeHash)
+{
+ // >1234<
+ const char string[] = "Hello dev null\n";
+ const char substring[] = " dev";
+
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string));
+ size_t start = 5;
+ size_t length = 4;
+
+
+ // compute the true hash
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, substring, length);
+ PARCCryptoHash *truthHash = parcCryptoHasher_Finalize(hasher);
+
+ // Compute the test hash
+ PARCCryptoHash *testHash = _ccnxWireFormatFacadeV1_ComputeBufferHash(buffer, hasher, start, length);
+
+ // Test
+ bool equals = parcCryptoHash_Equals(truthHash, testHash);
+ assertTrue(equals, "Hashes do not match")
+ {
+ PARCBuffer *truthBuffer = parcCryptoHash_GetDigest(truthHash);
+ PARCBuffer *testBuffer = parcCryptoHash_GetDigest(testHash);
+
+ printf("Expected:\n");
+ parcBuffer_Display(truthBuffer, 3);
+
+ printf("Got:\n");
+ parcBuffer_Display(testBuffer, 3);
+ }
+
+ parcCryptoHash_Release(&truthHash);
+ parcCryptoHash_Release(&testHash);
+ parcBuffer_Release(&buffer);
+ parcCryptoHasher_Release(&hasher);
+}
+
+// =======================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_WireFormatFacade);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/libccnxCommon_About.c b/libccnx-common/ccnx/common/libccnxCommon_About.c
new file mode 100644
index 00000000..88f44e17
--- /dev/null
+++ b/libccnx-common/ccnx/common/libccnxCommon_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.46e2c73a 2017-02-15T08:00:49Z
+
+#include "libccnxCommon_About.h"
+
+const char *libccnxCommon_What = "@(#)" "Libccnx Common " RELEASE_VERSION " 2017-02-20T22:04:39.067932"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+libccnxCommonAbout_Name(void)
+{
+ return "Libccnx Common";
+}
+
+const char *
+libccnxCommonAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+libccnxCommonAbout_About(void)
+{
+ return "Libccnx Common "RELEASE_VERSION " 2017-02-20T22:04:39.067932" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+libccnxCommonAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+libccnxCommonAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+libccnxCommonAbout_LongNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at:\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n";
+}
+
diff --git a/libccnx-common/ccnx/common/libccnxCommon_About.h b/libccnx-common/ccnx/common/libccnxCommon_About.h
new file mode 100755
index 00000000..af28dbdc
--- /dev/null
+++ b/libccnx-common/ccnx/common/libccnxCommon_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.46e2c73a 2017-02-15T08:00:49Z
+
+#ifndef libccnxCommon_About_h
+#define libccnxCommon_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *libccnxCommon_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *libccnxCommonAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *libccnxCommonAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *libccnxCommonAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *libccnxCommonAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *libccnxCommonAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *libccnxCommonAbout_LongNotice(void);
+
+#endif // libccnxCommon_About_h
diff --git a/libccnx-common/ccnx/common/test/.gitignore b/libccnx-common/ccnx/common/test/.gitignore
new file mode 100644
index 00000000..dc9b70b3
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/.gitignore
@@ -0,0 +1,22 @@
+./Makefile.am
+./Makefile.in
+test_ccnx_BufferChunker
+test_ccnx_FileChunker
+test_ccnx_Chunker
+test_ccnx_ContentObject
+test_ccnx_Interest
+test_ccnx_Json
+test_ccnx_Key
+test_ccnx_KeyListEntry
+test_ccnx_KeyLocator
+test_ccnx_Link
+test_ccnx_Manifest
+test_ccnx_ManifestSection
+test_ccnx_Name
+test_ccnx_NameLabel
+test_ccnx_NameSegment
+test_ccnx_NameSegmentNumber
+test_ccnx_NameType
+test_ccnx_NetworkBuffer
+test_ccnx_TimeStamp
+test_ccnx_WireFormatMessage
diff --git a/libccnx-common/ccnx/common/test/CMakeLists.txt b/libccnx-common/ccnx/common/test/CMakeLists.txt
new file mode 100644
index 00000000..4cf70a14
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/CMakeLists.txt
@@ -0,0 +1,29 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+configure_file(data.json data.json COPYONLY)
+
+set(TestsExpectedToPass
+ test_ccnx_ContentObject
+ test_ccnx_Interest
+ test_ccnx_InterestPayloadId
+ test_ccnx_InterestReturn
+ test_ccnx_KeyLocator
+ test_ccnx_KeystoreUtilities
+ test_ccnx_Link
+ test_ccnx_Manifest
+ test_ccnx_ManifestHashGroup
+ test_ccnx_Name
+ test_ccnx_NameLabel
+ test_ccnx_NameSegment
+ test_ccnx_NameSegmentNumber
+ test_ccnx_TimeStamp
+ test_ccnx_WireFormatMessage
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-common/ccnx/common/test/data.json b/libccnx-common/ccnx/common/test/data.json
new file mode 100644
index 00000000..a146f6ff
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/data.json
@@ -0,0 +1,2614 @@
+{
+ "array" : [
+ {
+ "id": 6104546,
+ "name": "-REPONAME",
+ "full_name": "mralexgray/-REPONAME",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/-REPONAME",
+ "description": null,
+ "fork": false,
+ "url": "https://api.github.com/repos/mralexgray/-REPONAME",
+ "forks_url": "https://api.github.com/repos/mralexgray/-REPONAME/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/-REPONAME/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/-REPONAME/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/-REPONAME/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/-REPONAME/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/-REPONAME/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/-REPONAME/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/-REPONAME/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/-REPONAME/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/-REPONAME/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/-REPONAME/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/-REPONAME/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/-REPONAME/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/-REPONAME/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/-REPONAME/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/-REPONAME/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/-REPONAME/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/-REPONAME/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/-REPONAME/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/-REPONAME/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/-REPONAME/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/-REPONAME/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/-REPONAME/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/-REPONAME/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/-REPONAME/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/-REPONAME/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/-REPONAME/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/-REPONAME/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/-REPONAME/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/-REPONAME/releases{/id}",
+ "created_at": "2012-10-06T16:37:39Z",
+ "updated_at": "2013-01-12T13:39:30Z",
+ "pushed_at": "2012-10-06T16:37:39Z",
+ "git_url": "git://github.com/mralexgray/-REPONAME.git",
+ "ssh_url": "git@github.com:mralexgray/-REPONAME.git",
+ "clone_url": "https://github.com/mralexgray/-REPONAME.git",
+ "svn_url": "https://github.com/mralexgray/-REPONAME",
+ "homepage": null,
+ "size": 48,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": null,
+ "has_issues": true,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 13121042,
+ "name": "ace",
+ "full_name": "mralexgray/ace",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/ace",
+ "description": "Ace (Ajax.org Cloud9 Editor)",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/ace",
+ "forks_url": "https://api.github.com/repos/mralexgray/ace/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/ace/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/ace/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/ace/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/ace/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/ace/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/ace/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/ace/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/ace/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/ace/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/ace/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/ace/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/ace/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/ace/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/ace/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/ace/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/ace/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/ace/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/ace/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/ace/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/ace/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/ace/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/ace/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/ace/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/ace/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/ace/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/ace/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/ace/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/ace/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/ace/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/ace/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/ace/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/ace/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/ace/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/ace/releases{/id}",
+ "created_at": "2013-09-26T11:58:10Z",
+ "updated_at": "2013-10-26T12:34:49Z",
+ "pushed_at": "2013-10-26T12:34:48Z",
+ "git_url": "git://github.com/mralexgray/ace.git",
+ "ssh_url": "git@github.com:mralexgray/ace.git",
+ "clone_url": "https://github.com/mralexgray/ace.git",
+ "svn_url": "https://github.com/mralexgray/ace",
+ "homepage": "http://ace.c9.io",
+ "size": 21080,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "JavaScript",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 10791045,
+ "name": "ACEView",
+ "full_name": "mralexgray/ACEView",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/ACEView",
+ "description": "Use the wonderful ACE editor in your Cocoa applications",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/ACEView",
+ "forks_url": "https://api.github.com/repos/mralexgray/ACEView/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/ACEView/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/ACEView/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/ACEView/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/ACEView/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/ACEView/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/ACEView/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/ACEView/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/ACEView/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/ACEView/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/ACEView/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/ACEView/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/ACEView/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/ACEView/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/ACEView/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/ACEView/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/ACEView/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/ACEView/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/ACEView/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/ACEView/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/ACEView/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/ACEView/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/ACEView/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/ACEView/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/ACEView/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/ACEView/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/ACEView/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/ACEView/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/ACEView/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/ACEView/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/ACEView/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/ACEView/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/ACEView/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/ACEView/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/ACEView/releases{/id}",
+ "created_at": "2013-06-19T12:15:04Z",
+ "updated_at": "2013-10-30T12:39:24Z",
+ "pushed_at": "2013-10-30T12:39:18Z",
+ "git_url": "git://github.com/mralexgray/ACEView.git",
+ "ssh_url": "git@github.com:mralexgray/ACEView.git",
+ "clone_url": "https://github.com/mralexgray/ACEView.git",
+ "svn_url": "https://github.com/mralexgray/ACEView",
+ "homepage": null,
+ "size": 1661,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 13623648,
+ "name": "ActiveLog",
+ "full_name": "mralexgray/ActiveLog",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/ActiveLog",
+ "description": "Shut up all logs with active filter.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/ActiveLog",
+ "forks_url": "https://api.github.com/repos/mralexgray/ActiveLog/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/ActiveLog/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/ActiveLog/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/ActiveLog/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/ActiveLog/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/ActiveLog/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/ActiveLog/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/ActiveLog/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/ActiveLog/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/ActiveLog/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/ActiveLog/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/ActiveLog/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/ActiveLog/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/ActiveLog/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/ActiveLog/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/ActiveLog/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/ActiveLog/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/ActiveLog/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/ActiveLog/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/ActiveLog/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/ActiveLog/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/ActiveLog/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/ActiveLog/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/ActiveLog/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/ActiveLog/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/ActiveLog/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/ActiveLog/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/ActiveLog/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/ActiveLog/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/ActiveLog/releases{/id}",
+ "created_at": "2013-10-16T15:52:37Z",
+ "updated_at": "2013-10-16T15:52:37Z",
+ "pushed_at": "2011-07-03T06:28:59Z",
+ "git_url": "git://github.com/mralexgray/ActiveLog.git",
+ "ssh_url": "git@github.com:mralexgray/ActiveLog.git",
+ "clone_url": "https://github.com/mralexgray/ActiveLog.git",
+ "svn_url": "https://github.com/mralexgray/ActiveLog",
+ "homepage": "http://deepitpro.com/en/articles/ActiveLog/info/",
+ "size": 60,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 9716210,
+ "name": "adium",
+ "full_name": "mralexgray/adium",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/adium",
+ "description": "Official mirror of hg.adium.im",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/adium",
+ "forks_url": "https://api.github.com/repos/mralexgray/adium/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/adium/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/adium/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/adium/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/adium/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/adium/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/adium/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/adium/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/adium/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/adium/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/adium/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/adium/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/adium/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/adium/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/adium/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/adium/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/adium/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/adium/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/adium/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/adium/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/adium/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/adium/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/adium/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/adium/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/adium/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/adium/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/adium/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/adium/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/adium/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/adium/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/adium/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/adium/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/adium/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/adium/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/adium/releases{/id}",
+ "created_at": "2013-04-27T14:59:33Z",
+ "updated_at": "2013-04-27T14:59:33Z",
+ "pushed_at": "2013-04-26T16:43:53Z",
+ "git_url": "git://github.com/mralexgray/adium.git",
+ "ssh_url": "git@github.com:mralexgray/adium.git",
+ "clone_url": "https://github.com/mralexgray/adium.git",
+ "svn_url": "https://github.com/mralexgray/adium",
+ "homepage": null,
+ "size": 277719,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": false,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 12752329,
+ "name": "ADLivelyTableView",
+ "full_name": "mralexgray/ADLivelyTableView",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/ADLivelyTableView",
+ "description": "Lively UITableView",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/ADLivelyTableView",
+ "forks_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/releases{/id}",
+ "created_at": "2013-09-11T09:18:01Z",
+ "updated_at": "2013-09-11T09:18:03Z",
+ "pushed_at": "2012-05-10T10:40:15Z",
+ "git_url": "git://github.com/mralexgray/ADLivelyTableView.git",
+ "ssh_url": "git@github.com:mralexgray/ADLivelyTableView.git",
+ "clone_url": "https://github.com/mralexgray/ADLivelyTableView.git",
+ "svn_url": "https://github.com/mralexgray/ADLivelyTableView",
+ "homepage": "http://applidium.com/en/news/lively_uitableview/",
+ "size": 73,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 5697379,
+ "name": "AFIncrementalStore",
+ "full_name": "mralexgray/AFIncrementalStore",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AFIncrementalStore",
+ "description": "Core Data Persistence with AFNetworking, Done Right",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AFIncrementalStore",
+ "forks_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/releases{/id}",
+ "created_at": "2012-09-06T04:20:33Z",
+ "updated_at": "2013-01-12T03:15:29Z",
+ "pushed_at": "2012-09-01T22:46:25Z",
+ "git_url": "git://github.com/mralexgray/AFIncrementalStore.git",
+ "ssh_url": "git@github.com:mralexgray/AFIncrementalStore.git",
+ "clone_url": "https://github.com/mralexgray/AFIncrementalStore.git",
+ "svn_url": "https://github.com/mralexgray/AFIncrementalStore",
+ "homepage": null,
+ "size": 139,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 6969621,
+ "name": "AFNetworking",
+ "full_name": "mralexgray/AFNetworking",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AFNetworking",
+ "description": "A delightful iOS and OS X networking framework",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AFNetworking",
+ "forks_url": "https://api.github.com/repos/mralexgray/AFNetworking/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AFNetworking/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AFNetworking/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AFNetworking/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AFNetworking/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AFNetworking/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AFNetworking/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AFNetworking/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AFNetworking/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AFNetworking/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AFNetworking/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AFNetworking/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AFNetworking/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AFNetworking/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AFNetworking/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AFNetworking/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AFNetworking/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AFNetworking/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AFNetworking/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AFNetworking/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AFNetworking/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AFNetworking/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AFNetworking/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AFNetworking/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AFNetworking/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AFNetworking/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AFNetworking/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AFNetworking/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AFNetworking/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AFNetworking/releases{/id}",
+ "created_at": "2012-12-02T17:00:04Z",
+ "updated_at": "2014-01-24T07:14:33Z",
+ "pushed_at": "2014-01-24T07:14:32Z",
+ "git_url": "git://github.com/mralexgray/AFNetworking.git",
+ "ssh_url": "git@github.com:mralexgray/AFNetworking.git",
+ "clone_url": "https://github.com/mralexgray/AFNetworking.git",
+ "svn_url": "https://github.com/mralexgray/AFNetworking",
+ "homepage": "http://afnetworking.com",
+ "size": 4341,
+ "stargazers_count": 1,
+ "watchers_count": 1,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 1,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 9485541,
+ "name": "AGNSSplitView",
+ "full_name": "mralexgray/AGNSSplitView",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AGNSSplitView",
+ "description": "Simple NSSplitView additions.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AGNSSplitView",
+ "forks_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/releases{/id}",
+ "created_at": "2013-04-17T00:10:13Z",
+ "updated_at": "2013-04-17T00:10:13Z",
+ "pushed_at": "2013-02-26T00:32:32Z",
+ "git_url": "git://github.com/mralexgray/AGNSSplitView.git",
+ "ssh_url": "git@github.com:mralexgray/AGNSSplitView.git",
+ "clone_url": "https://github.com/mralexgray/AGNSSplitView.git",
+ "svn_url": "https://github.com/mralexgray/AGNSSplitView",
+ "homepage": null,
+ "size": 68,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 12767784,
+ "name": "AGScopeBar",
+ "full_name": "mralexgray/AGScopeBar",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AGScopeBar",
+ "description": "Custom scope bar implementation for Cocoa",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AGScopeBar",
+ "forks_url": "https://api.github.com/repos/mralexgray/AGScopeBar/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AGScopeBar/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AGScopeBar/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AGScopeBar/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AGScopeBar/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AGScopeBar/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AGScopeBar/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AGScopeBar/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AGScopeBar/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AGScopeBar/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AGScopeBar/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AGScopeBar/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AGScopeBar/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AGScopeBar/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AGScopeBar/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AGScopeBar/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AGScopeBar/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AGScopeBar/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AGScopeBar/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AGScopeBar/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AGScopeBar/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AGScopeBar/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AGScopeBar/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AGScopeBar/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AGScopeBar/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AGScopeBar/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AGScopeBar/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AGScopeBar/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AGScopeBar/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AGScopeBar/releases{/id}",
+ "created_at": "2013-09-11T21:06:54Z",
+ "updated_at": "2013-09-11T21:06:54Z",
+ "pushed_at": "2013-05-07T03:35:29Z",
+ "git_url": "git://github.com/mralexgray/AGScopeBar.git",
+ "ssh_url": "git@github.com:mralexgray/AGScopeBar.git",
+ "clone_url": "https://github.com/mralexgray/AGScopeBar.git",
+ "svn_url": "https://github.com/mralexgray/AGScopeBar",
+ "homepage": null,
+ "size": 64,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 9227846,
+ "name": "AHContentBrowser",
+ "full_name": "mralexgray/AHContentBrowser",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AHContentBrowser",
+ "description": "A Mac only webview that loads a fast readable version of the website if available.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AHContentBrowser",
+ "forks_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/releases{/id}",
+ "created_at": "2013-04-04T20:56:16Z",
+ "updated_at": "2013-04-04T20:56:16Z",
+ "pushed_at": "2013-03-13T17:38:23Z",
+ "git_url": "git://github.com/mralexgray/AHContentBrowser.git",
+ "ssh_url": "git@github.com:mralexgray/AHContentBrowser.git",
+ "clone_url": "https://github.com/mralexgray/AHContentBrowser.git",
+ "svn_url": "https://github.com/mralexgray/AHContentBrowser",
+ "homepage": "",
+ "size": 223,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 9167473,
+ "name": "AHLayout",
+ "full_name": "mralexgray/AHLayout",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AHLayout",
+ "description": "AHLayout",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AHLayout",
+ "forks_url": "https://api.github.com/repos/mralexgray/AHLayout/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AHLayout/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AHLayout/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AHLayout/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AHLayout/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AHLayout/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AHLayout/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AHLayout/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AHLayout/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AHLayout/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AHLayout/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AHLayout/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AHLayout/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AHLayout/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AHLayout/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AHLayout/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AHLayout/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AHLayout/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AHLayout/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AHLayout/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AHLayout/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AHLayout/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AHLayout/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AHLayout/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AHLayout/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AHLayout/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AHLayout/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AHLayout/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AHLayout/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AHLayout/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AHLayout/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AHLayout/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AHLayout/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AHLayout/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AHLayout/releases{/id}",
+ "created_at": "2013-04-02T10:10:30Z",
+ "updated_at": "2013-07-08T02:31:17Z",
+ "pushed_at": "2013-07-08T02:31:14Z",
+ "git_url": "git://github.com/mralexgray/AHLayout.git",
+ "ssh_url": "git@github.com:mralexgray/AHLayout.git",
+ "clone_url": "https://github.com/mralexgray/AHLayout.git",
+ "svn_url": "https://github.com/mralexgray/AHLayout",
+ "homepage": null,
+ "size": 359,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 18450201,
+ "name": "Airmail-Plug-In-Framework",
+ "full_name": "mralexgray/Airmail-Plug-In-Framework",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Airmail-Plug-In-Framework",
+ "description": "",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework",
+ "forks_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/releases{/id}",
+ "created_at": "2014-04-04T19:33:54Z",
+ "updated_at": "2014-04-04T19:33:54Z",
+ "pushed_at": "2014-03-27T15:42:19Z",
+ "git_url": "git://github.com/mralexgray/Airmail-Plug-In-Framework.git",
+ "ssh_url": "git@github.com:mralexgray/Airmail-Plug-In-Framework.git",
+ "clone_url": "https://github.com/mralexgray/Airmail-Plug-In-Framework.git",
+ "svn_url": "https://github.com/mralexgray/Airmail-Plug-In-Framework",
+ "homepage": null,
+ "size": 888,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": null,
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 5203219,
+ "name": "AJS-iTunes-API",
+ "full_name": "mralexgray/AJS-iTunes-API",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AJS-iTunes-API",
+ "description": "Cocoa wrapper for the iTunes search API - for iOS and Mac OSX projects",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API",
+ "forks_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/releases{/id}",
+ "created_at": "2012-07-27T10:20:58Z",
+ "updated_at": "2013-01-11T11:00:05Z",
+ "pushed_at": "2011-10-30T22:26:48Z",
+ "git_url": "git://github.com/mralexgray/AJS-iTunes-API.git",
+ "ssh_url": "git@github.com:mralexgray/AJS-iTunes-API.git",
+ "clone_url": "https://github.com/mralexgray/AJS-iTunes-API.git",
+ "svn_url": "https://github.com/mralexgray/AJS-iTunes-API",
+ "homepage": "",
+ "size": 103,
+ "stargazers_count": 1,
+ "watchers_count": 1,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 1,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 10093801,
+ "name": "Alcatraz",
+ "full_name": "mralexgray/Alcatraz",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Alcatraz",
+ "description": "The most awesome (and only) Xcode package manager!",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Alcatraz",
+ "forks_url": "https://api.github.com/repos/mralexgray/Alcatraz/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Alcatraz/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Alcatraz/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Alcatraz/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Alcatraz/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Alcatraz/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Alcatraz/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Alcatraz/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Alcatraz/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Alcatraz/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Alcatraz/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Alcatraz/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Alcatraz/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Alcatraz/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Alcatraz/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Alcatraz/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Alcatraz/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Alcatraz/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Alcatraz/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Alcatraz/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Alcatraz/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Alcatraz/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Alcatraz/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Alcatraz/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Alcatraz/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Alcatraz/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Alcatraz/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Alcatraz/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Alcatraz/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Alcatraz/releases{/id}",
+ "created_at": "2013-05-16T04:41:13Z",
+ "updated_at": "2014-03-19T20:38:35Z",
+ "pushed_at": "2014-03-19T12:50:37Z",
+ "git_url": "git://github.com/mralexgray/Alcatraz.git",
+ "ssh_url": "git@github.com:mralexgray/Alcatraz.git",
+ "clone_url": "https://github.com/mralexgray/Alcatraz.git",
+ "svn_url": "https://github.com/mralexgray/Alcatraz",
+ "homepage": "mneorr.github.com/Alcatraz",
+ "size": 3668,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": false,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 12916552,
+ "name": "alcatraz-packages",
+ "full_name": "mralexgray/alcatraz-packages",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/alcatraz-packages",
+ "description": "Package list repository for Alcatraz",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/alcatraz-packages",
+ "forks_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/releases{/id}",
+ "created_at": "2013-09-18T07:15:24Z",
+ "updated_at": "2013-09-18T07:15:25Z",
+ "pushed_at": "2013-09-09T07:51:48Z",
+ "git_url": "git://github.com/mralexgray/alcatraz-packages.git",
+ "ssh_url": "git@github.com:mralexgray/alcatraz-packages.git",
+ "clone_url": "https://github.com/mralexgray/alcatraz-packages.git",
+ "svn_url": "https://github.com/mralexgray/alcatraz-packages",
+ "homepage": "mneorr.github.com/Alcatraz",
+ "size": 482,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Ruby",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 10476467,
+ "name": "Alfred-Google-Translate",
+ "full_name": "mralexgray/Alfred-Google-Translate",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Alfred-Google-Translate",
+ "description": "Extension for Alfred that will do a Google translate for you",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate",
+ "forks_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/releases{/id}",
+ "created_at": "2013-06-04T10:45:10Z",
+ "updated_at": "2013-06-04T10:45:10Z",
+ "pushed_at": "2013-01-12T19:39:03Z",
+ "git_url": "git://github.com/mralexgray/Alfred-Google-Translate.git",
+ "ssh_url": "git@github.com:mralexgray/Alfred-Google-Translate.git",
+ "clone_url": "https://github.com/mralexgray/Alfred-Google-Translate.git",
+ "svn_url": "https://github.com/mralexgray/Alfred-Google-Translate",
+ "homepage": null,
+ "size": 103,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Shell",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 5524019,
+ "name": "Amber",
+ "full_name": "mralexgray/Amber",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Amber",
+ "description": "Fork of the difficult-to-deal-with Amber.framework",
+ "fork": false,
+ "url": "https://api.github.com/repos/mralexgray/Amber",
+ "forks_url": "https://api.github.com/repos/mralexgray/Amber/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Amber/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Amber/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Amber/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Amber/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Amber/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Amber/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Amber/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Amber/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Amber/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Amber/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Amber/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Amber/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Amber/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Amber/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Amber/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Amber/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Amber/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Amber/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Amber/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Amber/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Amber/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Amber/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Amber/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Amber/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Amber/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Amber/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Amber/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Amber/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Amber/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Amber/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Amber/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Amber/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Amber/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Amber/releases{/id}",
+ "created_at": "2012-08-23T10:38:24Z",
+ "updated_at": "2013-01-11T22:25:35Z",
+ "pushed_at": "2012-08-23T10:38:25Z",
+ "git_url": "git://github.com/mralexgray/Amber.git",
+ "ssh_url": "git@github.com:mralexgray/Amber.git",
+ "clone_url": "https://github.com/mralexgray/Amber.git",
+ "svn_url": "https://github.com/mralexgray/Amber",
+ "homepage": null,
+ "size": 48,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": null,
+ "has_issues": true,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 10809060,
+ "name": "Amethyst",
+ "full_name": "mralexgray/Amethyst",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Amethyst",
+ "description": "Tiling window manager for OS X.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Amethyst",
+ "forks_url": "https://api.github.com/repos/mralexgray/Amethyst/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Amethyst/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Amethyst/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Amethyst/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Amethyst/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Amethyst/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Amethyst/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Amethyst/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Amethyst/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Amethyst/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Amethyst/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Amethyst/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Amethyst/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Amethyst/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Amethyst/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Amethyst/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Amethyst/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Amethyst/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Amethyst/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Amethyst/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Amethyst/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Amethyst/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Amethyst/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Amethyst/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Amethyst/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Amethyst/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Amethyst/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Amethyst/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Amethyst/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Amethyst/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Amethyst/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Amethyst/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Amethyst/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Amethyst/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Amethyst/releases{/id}",
+ "created_at": "2013-06-20T00:34:22Z",
+ "updated_at": "2013-06-20T00:34:22Z",
+ "pushed_at": "2013-06-18T02:54:11Z",
+ "git_url": "git://github.com/mralexgray/Amethyst.git",
+ "ssh_url": "git@github.com:mralexgray/Amethyst.git",
+ "clone_url": "https://github.com/mralexgray/Amethyst.git",
+ "svn_url": "https://github.com/mralexgray/Amethyst",
+ "homepage": "http://ianyh.github.io/Amethyst/",
+ "size": 12623,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 3684286,
+ "name": "Animated-Paths",
+ "full_name": "mralexgray/Animated-Paths",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Animated-Paths",
+ "description": "Demo project: Animating the drawing of a CGPath with CAShapeLayer.strokeEnd",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Animated-Paths",
+ "forks_url": "https://api.github.com/repos/mralexgray/Animated-Paths/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Animated-Paths/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Animated-Paths/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Animated-Paths/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Animated-Paths/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Animated-Paths/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Animated-Paths/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Animated-Paths/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Animated-Paths/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Animated-Paths/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Animated-Paths/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Animated-Paths/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Animated-Paths/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Animated-Paths/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Animated-Paths/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Animated-Paths/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Animated-Paths/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Animated-Paths/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Animated-Paths/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Animated-Paths/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Animated-Paths/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Animated-Paths/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Animated-Paths/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Animated-Paths/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Animated-Paths/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Animated-Paths/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Animated-Paths/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Animated-Paths/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Animated-Paths/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Animated-Paths/releases{/id}",
+ "created_at": "2012-03-11T02:56:38Z",
+ "updated_at": "2013-01-08T04:12:21Z",
+ "pushed_at": "2010-12-30T20:56:51Z",
+ "git_url": "git://github.com/mralexgray/Animated-Paths.git",
+ "ssh_url": "git@github.com:mralexgray/Animated-Paths.git",
+ "clone_url": "https://github.com/mralexgray/Animated-Paths.git",
+ "svn_url": "https://github.com/mralexgray/Animated-Paths",
+ "homepage": "http://oleb.net/blog/2010/12/animating-drawing-of-cgpath-with-cashapelayer/",
+ "size": 411,
+ "stargazers_count": 1,
+ "watchers_count": 1,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 1,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 16662874,
+ "name": "AnsiLove.framework",
+ "full_name": "mralexgray/AnsiLove.framework",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AnsiLove.framework",
+ "description": "Cocoa Framework for rendering ANSi / ASCII art",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AnsiLove.framework",
+ "forks_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/releases{/id}",
+ "created_at": "2014-02-09T08:30:27Z",
+ "updated_at": "2014-02-09T08:30:32Z",
+ "pushed_at": "2013-10-04T14:08:38Z",
+ "git_url": "git://github.com/mralexgray/AnsiLove.framework.git",
+ "ssh_url": "git@github.com:mralexgray/AnsiLove.framework.git",
+ "clone_url": "https://github.com/mralexgray/AnsiLove.framework.git",
+ "svn_url": "https://github.com/mralexgray/AnsiLove.framework",
+ "homepage": "http://byteproject.net",
+ "size": 3780,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "M",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": false,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 5189563,
+ "name": "ANTrackBar",
+ "full_name": "mralexgray/ANTrackBar",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/ANTrackBar",
+ "description": "An easy-to-use Cocoa seek bar with a pleasing appearance",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/ANTrackBar",
+ "forks_url": "https://api.github.com/repos/mralexgray/ANTrackBar/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/ANTrackBar/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/ANTrackBar/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/ANTrackBar/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/ANTrackBar/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/ANTrackBar/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/ANTrackBar/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/ANTrackBar/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/ANTrackBar/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/ANTrackBar/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/ANTrackBar/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/ANTrackBar/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/ANTrackBar/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/ANTrackBar/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/ANTrackBar/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/ANTrackBar/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/ANTrackBar/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/ANTrackBar/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/ANTrackBar/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/ANTrackBar/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/ANTrackBar/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/ANTrackBar/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/ANTrackBar/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/ANTrackBar/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/ANTrackBar/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/ANTrackBar/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/ANTrackBar/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/ANTrackBar/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/ANTrackBar/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/ANTrackBar/releases{/id}",
+ "created_at": "2012-07-26T08:17:22Z",
+ "updated_at": "2013-01-11T10:29:56Z",
+ "pushed_at": "2012-03-09T01:40:02Z",
+ "git_url": "git://github.com/mralexgray/ANTrackBar.git",
+ "ssh_url": "git@github.com:mralexgray/ANTrackBar.git",
+ "clone_url": "https://github.com/mralexgray/ANTrackBar.git",
+ "svn_url": "https://github.com/mralexgray/ANTrackBar",
+ "homepage": "",
+ "size": 94,
+ "stargazers_count": 1,
+ "watchers_count": 1,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 1,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 16240152,
+ "name": "AOP-in-Objective-C",
+ "full_name": "mralexgray/AOP-in-Objective-C",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/AOP-in-Objective-C",
+ "description": "An NSProxy based library for easily enabling AOP like functionality in Objective-C.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C",
+ "forks_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/releases{/id}",
+ "created_at": "2014-01-25T21:18:04Z",
+ "updated_at": "2014-02-12T16:23:21Z",
+ "pushed_at": "2014-02-12T16:23:20Z",
+ "git_url": "git://github.com/mralexgray/AOP-in-Objective-C.git",
+ "ssh_url": "git@github.com:mralexgray/AOP-in-Objective-C.git",
+ "clone_url": "https://github.com/mralexgray/AOP-in-Objective-C.git",
+ "svn_url": "https://github.com/mralexgray/AOP-in-Objective-C",
+ "homepage": "http://innoli.hu/en/opensource/",
+ "size": 340,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 1,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 1,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "travis-coveralls",
+ "master_branch": "travis-coveralls"
+ },
+ {
+ "id": 13141936,
+ "name": "Apaxy",
+ "full_name": "mralexgray/Apaxy",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Apaxy",
+ "description": "A simple, customisable theme for your Apache directory listing.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Apaxy",
+ "forks_url": "https://api.github.com/repos/mralexgray/Apaxy/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Apaxy/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Apaxy/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Apaxy/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Apaxy/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Apaxy/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Apaxy/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Apaxy/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Apaxy/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Apaxy/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Apaxy/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Apaxy/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Apaxy/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Apaxy/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Apaxy/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Apaxy/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Apaxy/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Apaxy/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Apaxy/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Apaxy/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Apaxy/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Apaxy/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Apaxy/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Apaxy/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Apaxy/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Apaxy/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Apaxy/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Apaxy/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Apaxy/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Apaxy/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Apaxy/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Apaxy/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Apaxy/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Apaxy/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Apaxy/releases{/id}",
+ "created_at": "2013-09-27T05:05:35Z",
+ "updated_at": "2013-09-27T05:05:36Z",
+ "pushed_at": "2013-08-02T16:01:32Z",
+ "git_url": "git://github.com/mralexgray/Apaxy.git",
+ "ssh_url": "git@github.com:mralexgray/Apaxy.git",
+ "clone_url": "https://github.com/mralexgray/Apaxy.git",
+ "svn_url": "https://github.com/mralexgray/Apaxy",
+ "homepage": null,
+ "size": 113,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "CSS",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 10048098,
+ "name": "appledoc",
+ "full_name": "mralexgray/appledoc",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/appledoc",
+ "description": "Objective-c code Apple style documentation set generator.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/appledoc",
+ "forks_url": "https://api.github.com/repos/mralexgray/appledoc/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/appledoc/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/appledoc/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/appledoc/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/appledoc/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/appledoc/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/appledoc/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/appledoc/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/appledoc/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/appledoc/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/appledoc/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/appledoc/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/appledoc/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/appledoc/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/appledoc/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/appledoc/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/appledoc/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/appledoc/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/appledoc/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/appledoc/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/appledoc/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/appledoc/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/appledoc/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/appledoc/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/appledoc/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/appledoc/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/appledoc/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/appledoc/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/appledoc/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/appledoc/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/appledoc/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/appledoc/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/appledoc/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/appledoc/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/appledoc/releases{/id}",
+ "created_at": "2013-05-14T05:45:44Z",
+ "updated_at": "2014-02-09T08:14:42Z",
+ "pushed_at": "2014-02-09T08:14:42Z",
+ "git_url": "git://github.com/mralexgray/appledoc.git",
+ "ssh_url": "git@github.com:mralexgray/appledoc.git",
+ "clone_url": "https://github.com/mralexgray/appledoc.git",
+ "svn_url": "https://github.com/mralexgray/appledoc",
+ "homepage": "http://gentlebytes.com",
+ "size": 10336,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": false,
+ "has_wiki": false,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 16160992,
+ "name": "Appstore-Through-Terminal",
+ "full_name": "mralexgray/Appstore-Through-Terminal",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Appstore-Through-Terminal",
+ "description": "A simple debian package, made for iPhone, to open the iOS AppStore through terminal. Simple. Slightly usless. My work as a beginner.",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal",
+ "forks_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/releases{/id}",
+ "created_at": "2014-01-23T03:21:34Z",
+ "updated_at": "2014-01-23T03:21:34Z",
+ "pushed_at": "2011-12-21T06:40:25Z",
+ "git_url": "git://github.com/mralexgray/Appstore-Through-Terminal.git",
+ "ssh_url": "git@github.com:mralexgray/Appstore-Through-Terminal.git",
+ "clone_url": "https://github.com/mralexgray/Appstore-Through-Terminal.git",
+ "svn_url": "https://github.com/mralexgray/Appstore-Through-Terminal",
+ "homepage": "http://getagripon.com/tillie/projects.html",
+ "size": 104,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Shell",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 13709216,
+ "name": "appweb-4",
+ "full_name": "mralexgray/appweb-4",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/appweb-4",
+ "description": "Appweb Embeddable Web Server 4",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/appweb-4",
+ "forks_url": "https://api.github.com/repos/mralexgray/appweb-4/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/appweb-4/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/appweb-4/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/appweb-4/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/appweb-4/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/appweb-4/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/appweb-4/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/appweb-4/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/appweb-4/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/appweb-4/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/appweb-4/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/appweb-4/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/appweb-4/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/appweb-4/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/appweb-4/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/appweb-4/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/appweb-4/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/appweb-4/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/appweb-4/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/appweb-4/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/appweb-4/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/appweb-4/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/appweb-4/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/appweb-4/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/appweb-4/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/appweb-4/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/appweb-4/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/appweb-4/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/appweb-4/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/appweb-4/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/appweb-4/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/appweb-4/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/appweb-4/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/appweb-4/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/appweb-4/releases{/id}",
+ "created_at": "2013-10-19T21:36:10Z",
+ "updated_at": "2013-10-19T21:36:11Z",
+ "pushed_at": "2013-10-19T00:35:06Z",
+ "git_url": "git://github.com/mralexgray/appweb-4.git",
+ "ssh_url": "git@github.com:mralexgray/appweb-4.git",
+ "clone_url": "https://github.com/mralexgray/appweb-4.git",
+ "svn_url": "https://github.com/mralexgray/appweb-4",
+ "homepage": "http://appwebserver.org",
+ "size": 58244,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 12501983,
+ "name": "arbor",
+ "full_name": "mralexgray/arbor",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/arbor",
+ "description": "a graph visualization library using web workers and jQuery",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/arbor",
+ "forks_url": "https://api.github.com/repos/mralexgray/arbor/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/arbor/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/arbor/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/arbor/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/arbor/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/arbor/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/arbor/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/arbor/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/arbor/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/arbor/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/arbor/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/arbor/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/arbor/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/arbor/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/arbor/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/arbor/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/arbor/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/arbor/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/arbor/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/arbor/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/arbor/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/arbor/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/arbor/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/arbor/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/arbor/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/arbor/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/arbor/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/arbor/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/arbor/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/arbor/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/arbor/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/arbor/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/arbor/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/arbor/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/arbor/releases{/id}",
+ "created_at": "2013-08-31T07:07:05Z",
+ "updated_at": "2013-08-31T07:07:06Z",
+ "pushed_at": "2012-05-28T00:47:58Z",
+ "git_url": "git://github.com/mralexgray/arbor.git",
+ "ssh_url": "git@github.com:mralexgray/arbor.git",
+ "clone_url": "https://github.com/mralexgray/arbor.git",
+ "svn_url": "https://github.com/mralexgray/arbor",
+ "homepage": "http://arborjs.org",
+ "size": 237,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "JavaScript",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 13537888,
+ "name": "Archimedes",
+ "full_name": "mralexgray/Archimedes",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/Archimedes",
+ "description": "Geometry functions for Cocoa and Cocoa Touch",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/Archimedes",
+ "forks_url": "https://api.github.com/repos/mralexgray/Archimedes/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/Archimedes/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/Archimedes/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/Archimedes/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/Archimedes/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/Archimedes/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/Archimedes/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/Archimedes/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/Archimedes/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/Archimedes/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/Archimedes/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/Archimedes/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/Archimedes/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/Archimedes/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/Archimedes/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/Archimedes/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/Archimedes/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/Archimedes/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/Archimedes/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/Archimedes/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/Archimedes/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/Archimedes/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/Archimedes/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/Archimedes/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/Archimedes/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/Archimedes/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/Archimedes/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/Archimedes/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/Archimedes/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/Archimedes/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/Archimedes/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/Archimedes/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/Archimedes/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/Archimedes/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/Archimedes/releases{/id}",
+ "created_at": "2013-10-13T11:08:19Z",
+ "updated_at": "2014-04-06T00:41:21Z",
+ "pushed_at": "2014-04-06T00:41:20Z",
+ "git_url": "git://github.com/mralexgray/Archimedes.git",
+ "ssh_url": "git@github.com:mralexgray/Archimedes.git",
+ "clone_url": "https://github.com/mralexgray/Archimedes.git",
+ "svn_url": "https://github.com/mralexgray/Archimedes",
+ "homepage": null,
+ "size": 217,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "master_branch": "master"
+ },
+ {
+ "id": 5260205,
+ "name": "arrsync",
+ "full_name": "mralexgray/arrsync",
+ "owner": {
+ "login": "mralexgray",
+ "id": 262517,
+ "avatar_url": "https://avatars.githubusercontent.com/u/262517?",
+ "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1",
+ "url": "https://api.github.com/users/mralexgray",
+ "html_url": "https://github.com/mralexgray",
+ "followers_url": "https://api.github.com/users/mralexgray/followers",
+ "following_url": "https://api.github.com/users/mralexgray/following{/other_user}",
+ "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions",
+ "organizations_url": "https://api.github.com/users/mralexgray/orgs",
+ "repos_url": "https://api.github.com/users/mralexgray/repos",
+ "events_url": "https://api.github.com/users/mralexgray/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/mralexgray/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/mralexgray/arrsync",
+ "description": "",
+ "fork": true,
+ "url": "https://api.github.com/repos/mralexgray/arrsync",
+ "forks_url": "https://api.github.com/repos/mralexgray/arrsync/forks",
+ "keys_url": "https://api.github.com/repos/mralexgray/arrsync/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/mralexgray/arrsync/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/mralexgray/arrsync/teams",
+ "hooks_url": "https://api.github.com/repos/mralexgray/arrsync/hooks",
+ "issue_events_url": "https://api.github.com/repos/mralexgray/arrsync/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/mralexgray/arrsync/events",
+ "assignees_url": "https://api.github.com/repos/mralexgray/arrsync/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/mralexgray/arrsync/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/mralexgray/arrsync/tags",
+ "blobs_url": "https://api.github.com/repos/mralexgray/arrsync/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/mralexgray/arrsync/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/mralexgray/arrsync/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/mralexgray/arrsync/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/mralexgray/arrsync/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/mralexgray/arrsync/languages",
+ "stargazers_url": "https://api.github.com/repos/mralexgray/arrsync/stargazers",
+ "contributors_url": "https://api.github.com/repos/mralexgray/arrsync/contributors",
+ "subscribers_url": "https://api.github.com/repos/mralexgray/arrsync/subscribers",
+ "subscription_url": "https://api.github.com/repos/mralexgray/arrsync/subscription",
+ "commits_url": "https://api.github.com/repos/mralexgray/arrsync/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/mralexgray/arrsync/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/mralexgray/arrsync/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/mralexgray/arrsync/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/mralexgray/arrsync/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/mralexgray/arrsync/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/mralexgray/arrsync/merges",
+ "archive_url": "https://api.github.com/repos/mralexgray/arrsync/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/mralexgray/arrsync/downloads",
+ "issues_url": "https://api.github.com/repos/mralexgray/arrsync/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/mralexgray/arrsync/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/mralexgray/arrsync/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/mralexgray/arrsync/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/mralexgray/arrsync/labels{/name}",
+ "releases_url": "https://api.github.com/repos/mralexgray/arrsync/releases{/id}",
+ "created_at": "2012-08-01T14:21:49Z",
+ "updated_at": "2013-01-11T13:12:21Z",
+ "pushed_at": "2011-05-09T18:56:56Z",
+ "git_url": "git://github.com/mralexgray/arrsync.git",
+ "ssh_url": "git@github.com:mralexgray/arrsync.git",
+ "clone_url": "https://github.com/mralexgray/arrsync.git",
+ "svn_url": "https://github.com/mralexgray/arrsync",
+ "homepage": "",
+ "size": 194,
+ "stargazers_count": 2,
+ "watchers_count": 2,
+ "language": "Objective-C",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 2,
+ "default_branch": "master",
+ "master_branch": "master"
+ }
+]
+} \ No newline at end of file
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_ContentObject.c b/libccnx-common/ccnx/common/test/test_ccnx_ContentObject.c
new file mode 100755
index 00000000..20ed8c13
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_ContentObject.c
@@ -0,0 +1,634 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_ContentObject.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+
+typedef struct test_data {
+ CCNxContentObjectInterface impl;
+ CCNxName *name;
+ CCNxContentObject *contentObject;
+ CCNxContentObject *namelessContentObject;
+} TestData;
+
+LONGBOW_TEST_RUNNER(ccnx_ContentObject)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(EmptyImpl);
+}
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/default/testData/content");
+ PARCBuffer *payload = parcBuffer_WrapCString("hello");
+
+ data->impl = CCNxContentObjectFacadeV1_Implementation;
+ data->name = name;
+ data->contentObject = ccnxContentObject_CreateWithImplAndPayload(&data->impl, name, CCNxPayloadType_DATA, payload);
+ data->namelessContentObject = ccnxContentObject_CreateWithImplAndPayload(&data->impl, NULL, CCNxPayloadType_DATA, payload);
+
+ parcBuffer_Release(&payload);
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ if (data->contentObject) {
+ ccnxContentObject_Release(&data->contentObject);
+ }
+ if (data->namelessContentObject) {
+ ccnxContentObject_Release(&data->namelessContentObject);
+ }
+ if (data->name) {
+ ccnxName_Release(&data->name);
+ }
+
+ parcMemory_Deallocate((void **) &data);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_ContentObject)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_ContentObject)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_SetSignature);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_GetKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_CreateWithNameAndPayload);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_CreateWithPayload);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_HasFinalChunkNumber);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_GetSetFinalChunkNumber);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_GetName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_GetNameWithNameless);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_GetPayload);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_GetPayloadType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_AcquireRelease);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_HasExpiryTime);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_SetGetExpiryTime);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_Display);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_CreateWithNameAndPayload)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar");
+ PARCBuffer *payload = parcBuffer_Allocate(100);
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ ccnxContentObject_AssertValid(contentObject);
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&payload);
+ ccnxContentObject_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_CreateWithPayload)
+{
+ PARCBuffer *payload = parcBuffer_Allocate(100);
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithPayload(payload);
+ ccnxContentObject_AssertValid(contentObject);
+
+ parcBuffer_Release(&payload);
+ ccnxContentObject_Release(&contentObject);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_Equals)
+{
+ CCNxName *nameA = ccnxName_CreateFromCString("ccnx:/foo/bar/A");
+ PARCBuffer *payloadA = parcBuffer_Allocate(100);
+
+ CCNxContentObject *objectA = ccnxContentObject_CreateWithNameAndPayload(nameA, payloadA);
+ ccnxContentObject_AssertValid(objectA);
+
+ assertTrue(ccnxContentObject_Equals(objectA, objectA), "Expected same instance to be equal");
+
+ CCNxContentObject *objectA2 = ccnxContentObject_CreateWithNameAndPayload(nameA, payloadA);
+ ccnxContentObject_AssertValid(objectA2);
+
+ assertTrue(ccnxContentObject_Equals(objectA, objectA2), "Expected ContentObject with same payload and name to be equal");
+
+ CCNxName *nameB = ccnxName_CreateFromCString("ccnx:/foo/bar/B");
+ CCNxContentObject *objectB = ccnxContentObject_CreateWithNameAndPayload(nameB, payloadA);
+ ccnxContentObject_AssertValid(objectB);
+
+ assertFalse(ccnxContentObject_Equals(objectA, objectB), "Expected ContentObject with same payload and different name");
+
+ ccnxName_Release(&nameA);
+ ccnxName_Release(&nameB);
+ parcBuffer_Release(&payloadA);
+
+ ccnxContentObject_Release(&objectA);
+ ccnxContentObject_Release(&objectA2);
+ ccnxContentObject_Release(&objectB);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_AcquireRelease)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar");
+ PARCBuffer *payload = parcBuffer_Allocate(100);
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ ccnxContentObject_AssertValid(contentObject);
+
+ CCNxContentObject *reference = ccnxContentObject_Acquire(contentObject);
+ assertTrue(reference == contentObject, "Expected acquired reference to be equal to original");
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&payload);
+
+ ccnxContentObject_AssertValid(contentObject);
+ ccnxContentObject_AssertValid(reference);
+
+ ccnxContentObject_Release(&contentObject);
+
+ assertTrue(contentObject == NULL, "Expected contentObject pointer to be null");
+ ccnxContentObject_AssertValid(reference);
+
+ ccnxContentObject_Release(&reference);
+
+ assertTrue(reference == NULL, "Expected contentObject pointer to be null");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_HasFinalChunkNumber)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar");
+ PARCBuffer *payload = parcBuffer_Allocate(100);
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ assertFalse(ccnxContentObject_HasFinalChunkNumber(contentObject), "Expected no final chunk number");
+
+ ccnxContentObject_SetFinalChunkNumber(contentObject, 100);
+ ccnxContentObject_AssertValid(contentObject);
+ assertTrue(ccnxContentObject_HasFinalChunkNumber(contentObject), "Expected HasFinalChunkNumber to return true");
+ assertTrue(ccnxContentObject_GetFinalChunkNumber(contentObject) == 100, "Expected final chunk number to be 100");
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&payload);
+ ccnxContentObject_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_GetSetFinalChunkNumber)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar");
+ PARCBuffer *payload = parcBuffer_Allocate(100);
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+
+ ccnxContentObject_SetFinalChunkNumber(contentObject, 100);
+ ccnxContentObject_AssertValid(contentObject);
+ assertTrue(ccnxContentObject_GetFinalChunkNumber(contentObject) == 100, "Expected final chunk number to be 100");
+
+ ccnxContentObject_SetFinalChunkNumber(contentObject, 20010);
+ ccnxContentObject_AssertValid(contentObject);
+ assertTrue(ccnxContentObject_GetFinalChunkNumber(contentObject) == 20010, "Expected final chunk number to be 20010");
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&payload);
+ ccnxContentObject_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_GetName)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar/baz");
+ PARCBuffer *payload = parcBuffer_Allocate(100);
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ ccnxContentObject_AssertValid(contentObject);
+
+ CCNxName *actual = ccnxContentObject_GetName(contentObject);
+
+ assertTrue(actual == name, "Expected GetName() to return the original CCNxName");
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&payload);
+ ccnxContentObject_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_GetNameWithNameless)
+{
+ PARCBuffer *payload = parcBuffer_Allocate(100);
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithPayload(payload);
+ ccnxContentObject_AssertValid(contentObject);
+
+ CCNxName *actual = ccnxContentObject_GetName(contentObject);
+
+ assertNull(actual, "Nameless CCNxContentObjects have no name and must therefore be null.");
+
+ parcBuffer_Release(&payload);
+ ccnxContentObject_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_GetPayload)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar");
+ PARCBuffer *payload = parcBuffer_Allocate(100);
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ ccnxContentObject_AssertValid(contentObject);
+
+ PARCBuffer *actual = ccnxContentObject_GetPayload(contentObject);
+
+ assertTrue(actual == payload, "Expected GetPayload() to return the original PARCBuffer");
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&payload);
+ ccnxContentObject_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_GetPayloadType)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/name");
+ PARCBuffer *payload = parcBuffer_Allocate(100);
+
+ CCNxPayloadType types[] = {
+ CCNxPayloadType_DATA,
+ CCNxPayloadType_KEY,
+ CCNxPayloadType_LINK,
+ CCNxPayloadType_MANIFEST,
+ };
+
+
+ for (int i = 0; i < sizeof(types) / sizeof(CCNxPayloadType); i++) {
+ CCNxPayloadType type = types[i];
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, NULL);
+ ccnxContentObject_SetPayload(contentObject, type, payload);
+
+ assertTrue(ccnxContentObject_GetPayloadType(contentObject) == type, "Unexpected PayloadType");
+ ccnxContentObject_Release(&contentObject);
+ }
+
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_SetSignature)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/hello/dolly");
+ PARCBuffer *payload = parcBuffer_WrapCString("hello");
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+
+ PARCBuffer *keyId = parcBuffer_WrapCString("keyhash");
+ PARCBuffer *sigbits = parcBuffer_WrapCString("siggybits");
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, parcBuffer_Flip(sigbits));
+
+ ccnxContentObject_SetSignature(contentObject, keyId, signature, NULL);
+
+ parcBuffer_Release(&payload);
+ parcBuffer_Release(&sigbits);
+ parcBuffer_Release(&keyId);
+ parcSignature_Release(&signature);
+ ccnxName_Release(&name);
+ ccnxContentObject_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_GetKeyId)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/hello/dolly");
+ PARCBuffer *payload = parcBuffer_WrapCString("hello");
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+
+ assertNull(ccnxContentObject_GetKeyId(contentObject), "Expect NULL for KeyId here");
+
+ PARCBuffer *testKeyId = parcBuffer_WrapCString("keyhash");
+ PARCBuffer *sigbits = parcBuffer_WrapCString("siggybits");
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, parcBuffer_Flip(sigbits));
+
+ ccnxContentObject_SetSignature(contentObject, testKeyId, signature, NULL);
+
+ PARCBuffer *keyId = ccnxContentObject_GetKeyId(contentObject);
+
+ assertTrue(parcBuffer_Equals(keyId, testKeyId), "Expect key ids to match");
+
+ parcBuffer_Release(&payload);
+ parcBuffer_Release(&sigbits);
+ parcBuffer_Release(&keyId);
+ parcSignature_Release(&signature);
+ ccnxName_Release(&name);
+ ccnxContentObject_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_HasExpiryTime)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/hello/dolly");
+ PARCBuffer *payload = parcBuffer_WrapCString("hello");
+
+ // Use a V1 ContentObject, as V0 doesn't support ExpiryTime
+ CCNxContentObject *contentObject =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name, CCNxPayloadType_DATA, payload);
+
+
+ assertFalse(ccnxContentObject_HasExpiryTime(contentObject), "Expected no expiration time by default");
+
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+ ccnxContentObject_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_SetGetExpiryTime)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/hello/dolly");
+ PARCBuffer *payload = parcBuffer_WrapCString("hello");
+
+ // Use a V1 ContentObject, as V0 doesn't support ExpiryTime
+ CCNxContentObject *contentObject =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name, CCNxPayloadType_DATA, payload);
+
+ assertFalse(ccnxContentObject_HasExpiryTime(contentObject), "Expected no expiration time by default");
+
+ uint64_t expiryTime = 1010101ULL;
+ ccnxContentObject_SetExpiryTime(contentObject, expiryTime);
+
+ assertTrue(ccnxContentObject_HasExpiryTime(contentObject), "Expected the expiryTime to be set");
+ uint64_t retrievedTime = ccnxContentObject_GetExpiryTime(contentObject);
+ assertTrue(expiryTime == retrievedTime, "Did not retrieve expected expiryTime from ContentObject");
+
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+ ccnxContentObject_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, ccnxContentObject_GetExpiryTimeWithNoExpiryTime, .event = &LongBowTrapUnexpectedStateEvent)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/hello/dolly");
+ PARCBuffer *payload = parcBuffer_WrapCString("hello");
+
+ // Use a V1 ContentObject, as V0 doesn't support ExpiryTime
+ CCNxContentObject *contentObject =
+ ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name, CCNxPayloadType_DATA, payload);
+
+ // This should throw.
+ uint64_t retrievedTime = ccnxContentObject_GetExpiryTime(contentObject);
+ trapUnexpectedState("Expected to have thrown an exception when calling GetExpiryTime(), which returned %" PRIu64, retrievedTime);
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+ ccnxContentObject_Release(&contentObject);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxContentObject_Display)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/hello/dolly");
+ PARCBuffer *payload = parcBuffer_WrapCString("hello");
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+
+ ccnxContentObject_Display(contentObject, 0);
+
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+ ccnxContentObject_Release(&contentObject);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Empty Implementation Tests
+///////////////////////////////////////////////////////////////////////////
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetPayloadType, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.getPayloadType = NULL;
+
+ CCNxPayloadType type = ccnxContentObject_GetPayloadType(data->contentObject);
+ printf("We shouldn't get here. Payload = %d", type);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetPayload, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.getPayload = NULL;
+
+ PARCBuffer *payload = ccnxContentObject_GetPayload(data->contentObject);
+ printf("We shouldn't get here. Payload = %p", (void *) payload);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetPayload, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.setPayload = NULL;
+
+ ccnxContentObject_SetPayload(data->contentObject, CCNxPayloadType_DATA, NULL);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetName, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.getName = NULL;
+
+ CCNxName *name = ccnxContentObject_GetName(data->contentObject);
+ printf("We shouldn't get here. Name = %p", (void *) name);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetFinalChunkNumber, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.setFinalChunkNumber = NULL;
+
+ ccnxContentObject_SetFinalChunkNumber(data->contentObject, 100);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetFinalChunkNumber, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.getFinalChunkNumber = NULL;
+
+ ccnxContentObject_SetFinalChunkNumber(data->contentObject, 100);
+ ccnxContentObject_GetFinalChunkNumber(data->contentObject);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetFinalChunkNumberNoHas, .event = &LongBowTrapUnexpectedStateEvent)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.getFinalChunkNumber = NULL;
+
+ ccnxContentObject_GetFinalChunkNumber(data->contentObject);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_HasFinalChunkNumber, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.hasFinalChunkNumber = NULL;
+
+ if (ccnxContentObject_HasFinalChunkNumber(data->contentObject)) {
+ printf("Shouldn't get here");
+ }
+}
+
+LONGBOW_TEST_CASE(EmptyImpl, empty_HasExpiryTime)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.hasExpiryTime = NULL;
+
+ assertFalse(ccnxContentObject_HasExpiryTime(data->contentObject), "If no expiry time implementation, return false.");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetExpiryTime, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.setExpiryTime = NULL;
+
+ ccnxContentObject_SetExpiryTime(data->contentObject, 100);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetExpiryTime, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.getExpiryTime = NULL;
+
+ ccnxContentObject_SetExpiryTime(data->contentObject, 100);
+ uint64_t expiryTime = ccnxContentObject_GetExpiryTime(data->contentObject);
+ printf("We shouldn't get here, with expiryTime = %" PRIu64, expiryTime);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetExpiryTimeNoHas, .event = &LongBowTrapUnexpectedStateEvent)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.getExpiryTime = NULL;
+
+ uint64_t expiryTime = ccnxContentObject_GetExpiryTime(data->contentObject);
+ printf("We shouldn't get here, with expiryTime = %" PRIu64, expiryTime);
+}
+
+LONGBOW_TEST_CASE(EmptyImpl, empty_Display)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.display = NULL;
+
+ ccnxContentObject_Display(data->contentObject, 2);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_ToString, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.toString = NULL;
+
+ const char *expectedString = ccnxContentObject_ToString(data->contentObject);
+ if (expectedString != NULL) {
+ parcMemory_Deallocate((void **) &expectedString);
+ }
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_Equals, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.equals = NULL;
+
+ if (ccnxContentObject_Equals(data->contentObject, data->contentObject)) {
+ printf("Shouldn't get here");
+ }
+}
+
+LONGBOW_TEST_FIXTURE(EmptyImpl)
+{
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_Display);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_HasExpiryTime);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetExpiryTime);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetExpiryTimeNoHas);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetExpiryTime);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetFinalChunkNumber);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetFinalChunkNumber);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetFinalChunkNumberNoHas);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_HasFinalChunkNumber);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetPayload);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetPayloadType);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetPayload);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetName);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_ToString);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_Equals);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(EmptyImpl)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(EmptyImpl)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ContentObject);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_Interest.c b/libccnx-common/ccnx/common/test/test_ccnx_Interest.c
new file mode 100755
index 00000000..29debe9c
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_Interest.c
@@ -0,0 +1,725 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include <ccnx/common/ccnx_Interest.c>
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(ccnx_Interest)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(EmptyImpl);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_Interest)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_Interest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_Create);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_CreateSimple);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_Release);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_AssertValid);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_Equals_Same);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_Equals);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetLifetime);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_GetLifetime);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_GetName);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetGetPayload);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetPayloadWithId);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetPayloadAndId);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetGetHopLimit);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetKeyIdRestriction);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_GetKeyIdRestriction);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_GetContentObjectHashRestriction);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetContentObjectHashRestriction);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_ToString);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_Display);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_Create)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ PARCBuffer *key = parcBuffer_Allocate(8);
+ parcBuffer_PutUint64(key, 1234L);
+
+ CCNxInterest *interest = ccnxInterest_Create(name,
+ 15 * 1000, /* lifetime, 15 seconds in milliseconds */
+ key, /* KeyId */
+ NULL /* ContentObjectHash */
+ );
+ ccnxName_Release(&name);
+ parcBuffer_Release(&key);
+ ccnxInterest_Release(&interest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_CreateSimple)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+
+ ccnxName_Release(&name);
+ ccnxInterest_Release(&interest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_Release)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+
+ CCNxInterest *reference = ccnxInterest_Acquire(interest);
+
+ ccnxName_Release(&name);
+ ccnxInterest_Release(&interest);
+ ccnxInterest_Release(&reference);
+
+ assertNull(interest, "Expected ccnxInterest_Release to null the pointer.");
+ assertNull(reference, "Expected ccnxInterest_Release to null the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_AssertValid)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+
+ ccnxInterest_AssertValid(interest);
+
+ ccnxName_Release(&name);
+ ccnxInterest_Release(&interest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_Equals_Same)
+{
+ CCNxName *nameA = ccnxName_CreateFromCString("lci:/name");
+ PARCBuffer *key = parcBuffer_Allocate(8);
+ parcBuffer_PutUint64(key, 1234L);
+
+ CCNxInterest *interestA = ccnxInterest_Create(nameA,
+ CCNxInterestDefault_LifetimeMilliseconds, /* lifetime */
+ key, /* KeyId */
+ NULL /* ContentObjectHash */
+ );
+
+ assertTrue(ccnxInterest_Equals(interestA, interestA), "Expected the same interest to be equal.");
+
+ assertFalse(ccnxInterest_Equals(interestA, NULL), "Did not expect NULL to equal an Interest");
+
+
+ ccnxName_Release(&nameA);
+ parcBuffer_Release(&key);
+ ccnxInterest_Release(&interestA);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_Equals)
+{
+ CCNxName *nameA = ccnxName_CreateFromCString("lci:/name");
+ PARCBuffer *keyA = parcBuffer_Allocate(8);
+ parcBuffer_PutUint64(keyA, 1234L);
+
+ CCNxInterest *interestA = ccnxInterest_Create(nameA,
+ 1000, /* lifetime */
+ keyA, /* KeyId */
+ NULL /* ContentObjectHash */
+ );
+
+ CCNxName *nameB = ccnxName_CreateFromCString("lci:/name");
+ PARCBuffer *keyB = parcBuffer_Allocate(8);
+ parcBuffer_PutUint64(keyB, 1234L);
+ CCNxInterest *interestB = ccnxInterest_Create(nameB,
+ 1000, /* lifetime */
+ keyB, /* KeyId */
+ NULL /* ContentObjectHash */
+ );
+
+ assertTrue(ccnxInterest_Equals(interestA, interestB), "Expected equivalent interests to be equal.");
+
+ ccnxName_Release(&nameA);
+ ccnxName_Release(&nameB);
+ parcBuffer_Release(&keyA);
+ parcBuffer_Release(&keyB);
+ ccnxInterest_Release(&interestA);
+ ccnxInterest_Release(&interestB);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_SetLifetime)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ PARCBuffer *key = parcBuffer_Allocate(8);
+ parcBuffer_PutUint64(key, 1234L);
+
+ uint32_t lifetime = 5000; // 5 seconds, in milliseconds
+
+ CCNxInterest *interest = ccnxInterest_Create(name,
+ lifetime, /* lifetime */
+ key, /* KeyId */
+ NULL /* ContentObjectHash */
+ );
+
+ uint32_t actual = ccnxInterest_GetLifetime(interest);
+
+ assertTrue(actual == lifetime, "Expected the retrieved lifetime to be equal to the assigned one.");
+
+ lifetime = 2000;
+ ccnxInterest_SetLifetime(interest, lifetime);
+ actual = ccnxInterest_GetLifetime(interest);
+
+ assertTrue(actual == lifetime, "Expected the retrieved lifetime to be equal to the assigned one.");
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&key);
+ ccnxInterest_Release(&interest);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_GetLifetime)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ PARCBuffer *key = parcBuffer_Allocate(8);
+ parcBuffer_PutUint64(key, 1234L);
+
+ uint32_t lifetime = 5000; // 5 seconds, in milliseconds
+
+ CCNxInterest *interest = ccnxInterest_Create(name,
+ lifetime, /* lifetime */
+ key, /* KeyId */
+ NULL /* ContentObjectHash */
+ );
+
+ uint32_t actual = ccnxInterest_GetLifetime(interest);
+
+ assertTrue(actual == lifetime, "Expected the retrieved lifetime to be equal to the assigned one.");
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&key);
+ ccnxInterest_Release(&interest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_GetName)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+
+ CCNxName *actual = ccnxInterest_GetName(interest);
+ assertTrue(ccnxName_Equals(name, actual), "Expected the same name.");
+
+ ccnxName_Release(&name);
+ ccnxInterest_Release(&interest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_SetKeyIdRestriction)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ PARCBuffer *key = parcBuffer_Allocate(8);
+ parcBuffer_PutUint64(key, 1234L);
+
+ CCNxInterest *interest = ccnxInterest_Create(name, 3000, NULL, NULL);
+ ccnxInterest_SetKeyIdRestriction(interest, key);
+ PARCBuffer *actual = ccnxInterest_GetKeyIdRestriction(interest);
+
+ actual = ccnxInterest_GetKeyIdRestriction(interest);
+ assertTrue(actual == key, "Expected retrieved key to be the same as assigned");
+
+ ccnxName_Release(&name);
+ ccnxInterest_Release(&interest);
+ parcBuffer_Release(&key);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_GetKeyIdRestriction)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ PARCBuffer *key = parcBuffer_Allocate(8);
+ parcBuffer_PutUint64(key, 1234L);
+
+ CCNxInterest *interest = ccnxInterest_Create(name, 3000, key, NULL);
+
+ PARCBuffer *actual = ccnxInterest_GetKeyIdRestriction(interest);
+
+ actual = ccnxInterest_GetKeyIdRestriction(interest);
+ assertTrue(actual == key, "Expected retrieved key to be the same as assigned");
+
+ ccnxName_Release(&name);
+ ccnxInterest_Release(&interest);
+ parcBuffer_Release(&key);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_SetContentObjectHashRestriction)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ PARCBuffer *coh = parcBuffer_Allocate(8);
+ parcBuffer_PutUint64(coh, 77573L);
+
+ CCNxInterest *interest = ccnxInterest_Create(name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL);
+
+ PARCBuffer *actual = ccnxInterest_GetContentObjectHashRestriction(interest);
+ assertNull(actual, "Expected retrieved ContentObjectHash to be initially NULL");
+
+ ccnxInterest_SetContentObjectHashRestriction(interest, coh);
+ actual = ccnxInterest_GetContentObjectHashRestriction(interest);
+
+ assertTrue(actual == coh, "Expected retrieved ContentObjectHash to be the same as assigned");
+
+ // Re-setting is not yet supported. At the moment, you can only put the COHR once.
+ // Now change it, and validate.
+ //PARCBuffer *coh2 = parcBuffer_Allocate(8);
+ //parcBuffer_PutUint64(coh2, 3262L);
+ //ccnxInterest_SetContentObjectHashRestriction(interest, coh2);
+ //actual = ccnxInterest_GetContentObjectHashRestriction(interest);
+ //assertTrue(actual == coh2, "Expected retrieved ContentObjectHash to be the same as assigned");
+
+ ccnxName_Release(&name);
+ ccnxInterest_Release(&interest);
+ parcBuffer_Release(&coh);
+ //parcBuffer_Release(&coh2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_GetContentObjectHashRestriction)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ PARCBuffer *coh = parcBuffer_Allocate(8);
+ parcBuffer_PutUint64(coh, 1234L);
+
+ CCNxInterest *interest = ccnxInterest_Create(name, CCNxInterestDefault_LifetimeMilliseconds, NULL, coh);
+
+ PARCBuffer *actual = ccnxInterest_GetContentObjectHashRestriction(interest);
+
+ assertTrue(actual == coh, "Expected retrieved ContentObjectHash to be the same as assigned");
+
+ ccnxName_Release(&name);
+ ccnxInterest_Release(&interest);
+ parcBuffer_Release(&coh);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_SetGetPayload)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ CCNxName *origNameCopy = ccnxName_Copy(name);
+
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ if (impl->getPayload) {
+ assertNull(ccnxInterest_GetPayload(interest), "Expected a NULL payload");
+ }
+
+ if (impl->getPayload && impl->setPayload) {
+ PARCBuffer *payload = parcBuffer_WrapCString("impls have pimples");
+ ccnxInterest_SetPayload(interest, payload);
+
+ PARCBuffer *payloadOut = ccnxInterest_GetPayload(interest);
+
+ assertTrue(parcBuffer_Equals(payload, payloadOut), "Expected an equal buffer");
+
+ CCNxName *nameAfterPayload = ccnxInterest_GetName(interest);
+ assertTrue(ccnxName_Equals(nameAfterPayload, origNameCopy), "Expected an unmodified name");
+
+ parcBuffer_Release(&payload);
+ }
+ ccnxName_Release(&name);
+ ccnxName_Release(&origNameCopy);
+ ccnxInterest_Release(&interest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_SetPayloadAndId)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ if (impl->getPayload) {
+ assertNull(ccnxInterest_GetPayload(interest), "Expected a NULL payload");
+ }
+
+ if (impl->getPayload && impl->setPayload) {
+ PARCBuffer *payload = parcBuffer_WrapCString("impls have pimples");
+
+ ccnxInterest_SetPayloadAndId(interest, payload);
+
+ PARCBuffer *payloadOut = ccnxInterest_GetPayload(interest);
+
+ assertTrue(parcBuffer_Equals(payload, payloadOut), "Expected an equal buffer");
+
+ CCNxName *nameAfterPayload = ccnxInterest_GetName(interest);
+ CCNxNameSegment *segment = ccnxName_GetSegment(nameAfterPayload, ccnxName_GetSegmentCount(nameAfterPayload) - 1);
+
+ assertTrue(ccnxNameSegment_GetType(segment) == CCNxNameLabelType_PAYLOADID, "Expected to find a payload ID appended to the name");
+
+ parcBuffer_Release(&payload);
+ }
+ ccnxName_Release(&name);
+ ccnxInterest_Release(&interest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_SetPayloadWithId)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ CCNxName *origNameCopy = ccnxName_Copy(name);
+
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ if (impl->getPayload) {
+ assertNull(ccnxInterest_GetPayload(interest), "Expected a NULL payload");
+ }
+
+ if (impl->getPayload && impl->setPayload) {
+ PARCBuffer *payload = parcBuffer_WrapCString("impls have pimples");
+ PARCBuffer *payloadIdBuffer = parcBuffer_WrapCString("payload Id buffer");
+
+ CCNxInterestPayloadId *payloadId = ccnxInterestPayloadId_Create(payloadIdBuffer,
+ CCNxInterestPayloadId_TypeCode_App + 2);
+
+ ccnxInterest_SetPayloadWithId(interest, payload, payloadId);
+
+ PARCBuffer *payloadOut = ccnxInterest_GetPayload(interest);
+
+ assertTrue(parcBuffer_Equals(payload, payloadOut), "Expected an equal buffer");
+
+ CCNxName *nameAfterPayload = ccnxInterest_GetName(interest);
+ CCNxNameSegment *segment = ccnxName_GetSegment(nameAfterPayload, ccnxName_GetSegmentCount(nameAfterPayload) - 1);
+
+ assertTrue(ccnxNameSegment_GetType(segment) == CCNxNameLabelType_PAYLOADID, "Expected to find a payload ID appended to the name");
+
+ CCNxInterestPayloadId *outId = ccnxInterestPayloadId_CreateFromSegmentInName(nameAfterPayload);
+ assertTrue(ccnxInterestPayloadId_Equals(outId, payloadId), "expected to see the same payload Id after setting the payload");
+
+ ccnxInterestPayloadId_Release(&payloadId);
+ ccnxInterestPayloadId_Release(&outId);
+
+ parcBuffer_Release(&payload);
+ parcBuffer_Release(&payloadIdBuffer);
+ }
+ ccnxName_Release(&name);
+ ccnxName_Release(&origNameCopy);
+ ccnxInterest_Release(&interest);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_SetGetHopLimit)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+
+ if (impl->getHopLimit) {
+ assertTrue(ccnxInterest_GetHopLimit(interest) == CCNxInterestDefault_HopLimit, "Expected the default hop limit");
+ }
+
+ if (impl->setHopLimit && impl->getHopLimit) {
+ ccnxInterest_SetHopLimit(interest, 10);
+ assertTrue(ccnxInterest_GetHopLimit(interest) == 10, "Expected a hopLimit of 10");
+ ccnxInterest_SetHopLimit(interest, 20);
+ assertTrue(ccnxInterest_GetHopLimit(interest) == 20, "Expected a hopLimit of 20");
+ }
+
+ ccnxName_Release(&name);
+ ccnxInterest_Release(&interest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_ToString)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ CCNxInterest *interest = ccnxInterest_Create(name,
+ CCNxInterestDefault_LifetimeMilliseconds, /* lifetime */
+ NULL, /* KeyId */
+ NULL /* ContentObjectHash */
+ );
+
+ const char *expectedString = ccnxInterest_ToString(interest);
+ assertNotNull(expectedString, "Expected non-null result from ccnxInterest_ToString.");
+
+ parcMemory_Deallocate((void **) &expectedString);
+ ccnxName_Release(&name);
+ ccnxInterest_Release(&interest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterest_Display)
+{
+ PARCBuffer *coh = parcBuffer_Allocate(8);
+ parcBuffer_PutUint64(coh, 7778L);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ CCNxInterest *interest = ccnxInterest_Create(name,
+ 100, /* lifetime */
+ NULL, /* KeyId */
+ coh); /* ContentObjectHash */
+
+ ccnxInterest_Display(interest, 2);
+ ccnxName_Release(&name);
+ ccnxInterest_Release(&interest);
+ parcBuffer_Release(&coh);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Empty Implementation tests
+///////////////////////////////////////////////////////////////////////////////
+
+
+typedef struct test_data {
+ CCNxInterestInterface impl;
+ CCNxName *name;
+ CCNxInterest *interest;
+} TestData;
+
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/default/testData/content");
+
+ data->impl = CCNxInterestFacadeV1_Implementation; // This copies the struct each time.
+ data->name = name;
+ data->interest = ccnxInterest_CreateWithImpl(&data->impl, name, 100, NULL, NULL, 10);
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ if (data->interest) {
+ ccnxInterest_Release(&data->interest);
+ }
+ if (data->name) {
+ ccnxName_Release(&data->name);
+ }
+
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(EmptyImpl)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(EmptyImpl)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_CASE(EmptyImpl, empty_Display)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.display = NULL;
+
+ ccnxInterest_Display(data->interest, 2);
+}
+
+LONGBOW_TEST_CASE(EmptyImpl, empty_ToString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.toString = NULL;
+
+ const char *expectedString = ccnxInterest_ToString(data->interest);
+ if (expectedString != NULL) {
+ parcMemory_Deallocate((void **) &expectedString);
+ }
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetName, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.getName = NULL;
+
+ CCNxName *name = ccnxInterest_GetName(data->interest);
+ printf("Shouldn't get here. name = %p\n", (void *) name);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetHopLimit, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.setHopLimit = NULL;
+
+ if (ccnxInterest_SetHopLimit(data->interest, 10)) {
+ printf("Shouldn't get here");
+ }
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetHopLimit, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.getHopLimit = NULL;
+
+ uint32_t hopLimit = ccnxInterest_GetHopLimit(data->interest);
+ printf("Shouldn't get here. hopLimit = %u\n", hopLimit);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetLifetime, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.setLifetime = NULL;
+
+ if (ccnxInterest_SetLifetime(data->interest, 10)) {
+ printf("Shouldn't get here");
+ }
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetLifetime, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.getLifetime = NULL;
+
+ uint32_t lifetime = ccnxInterest_GetLifetime(data->interest);
+ printf("Shouldn't get here. lifetime = %u\n", lifetime);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetKeyIdRestriction, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.setKeyIdRestriction = NULL;
+
+ if (ccnxInterest_SetKeyIdRestriction(data->interest, NULL)) {
+ printf("Shouldn't get here");
+ }
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetKeyIdRestriction, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.getKeyIdRestriction = NULL;
+
+ PARCBuffer *keyIdRestriction = ccnxInterest_GetKeyIdRestriction(data->interest);
+ printf("Shouldn't get here. getKeyIdRestriction = %p\n", (void *) keyIdRestriction);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetContentObjectHashRestriction, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.setContentObjectHashRestriction = NULL;
+
+ if (ccnxInterest_SetContentObjectHashRestriction(data->interest, NULL)) {
+ printf("Shouldn't get here");
+ }
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetContentObjectHashRestriction, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.getContentObjectHashRestriction = NULL;
+
+ PARCBuffer *restriction = ccnxInterest_GetContentObjectHashRestriction(data->interest);
+ printf("Shouldn't get here. restriction = %p\n", (void *) restriction);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetPayload, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.setPayload = NULL;
+
+ if (ccnxInterest_SetPayload(data->interest, NULL)) {
+ printf("Shouldn't get here");
+ }
+}
+
+LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetPayload, .event = &LongBowTrapNotImplemented)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ data->impl.getPayload = NULL;
+
+ PARCBuffer *payload = ccnxInterest_GetPayload(data->interest);
+ printf("Shouldn't get here. payload = %p\n", (void *) payload);
+}
+
+LONGBOW_TEST_FIXTURE(EmptyImpl)
+{
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_Display);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_ToString);
+
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetName);
+
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetHopLimit);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetHopLimit);
+
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetLifetime);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetLifetime);
+
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetKeyIdRestriction);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetKeyIdRestriction);
+
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetContentObjectHashRestriction);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetContentObjectHashRestriction);
+
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetPayload);
+ LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetPayload);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_Interest);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_InterestPayloadId.c b/libccnx-common/ccnx/common/test/test_ccnx_InterestPayloadId.c
new file mode 100755
index 00000000..28e07643
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_InterestPayloadId.c
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include <config.h>
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <stdio.h>
+
+#include "../ccnx_InterestPayloadId.c"
+
+static const PARCMemoryInterface *_originalMemoryProvider;
+
+LONGBOW_TEST_RUNNER(ccnx_InterestPayloadId)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Error);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_InterestPayloadId)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_InterestPayloadId)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_CreateWithAppDefinedType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_CreateAsCryptoHash);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_CreateFromSegmentInName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_CreateFromSegmentInName_NotFound);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_GetNameSegment);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_GetValue);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_GetType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_NotEquals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_HashCode);
+}
+
+typedef struct {
+ uint8_t type;
+ PARCBuffer *value;
+} TestData;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->value = parcBuffer_WrapCString("123456789abcdef");
+ data->type = 42 + CCNxInterestPayloadId_TypeCode_App;
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ parcBuffer_Release(&data->value);
+ parcMemory_Deallocate((void **) &data);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ parcMemory_SetInterface(_originalMemoryProvider);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_CreateWithAppDefinedType)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t type = data->type;
+ PARCBuffer *value = parcBuffer_Acquire(data->value);
+ CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type);
+ assertNotNull(ipId, "Expect a non-NULL result from Create");
+ ccnxInterestPayloadId_AssertValid(ipId);
+
+ parcBuffer_Release(&value);
+
+ assertTrue(ccnxInterestPayloadId_IsValid(ipId), "Expected a valid CCNxInteresPayloadId.");
+ ccnxInterestPayloadId_Release(&ipId);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_CreateAsCryptoHash)
+{
+ PARCBuffer *value = parcBuffer_WrapCString("123456789abcdef");
+ CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_CreateAsSHA256Hash(value);
+ assertNotNull(ipId, "Expect a non-NULL result from CreateByHash");
+ ccnxInterestPayloadId_AssertValid(ipId);
+
+ parcBuffer_Release(&value);
+
+ assertTrue(ccnxInterestPayloadId_IsValid(ipId), "Expected a valid CCNxInteresPayloadId.");
+ ccnxInterestPayloadId_Release(&ipId);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_CreateFromSegmentInName)
+{
+ PARCBuffer *value = parcBuffer_WrapCString("123456789abcdef");
+ CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_CreateAsSHA256Hash(value);
+ parcBuffer_Release(&value);
+ assertNotNull(ipId, "Expect a non-NULL result from CreateByHash");
+ ccnxInterestPayloadId_AssertValid(ipId);
+ assertTrue(ccnxInterestPayloadId_IsValid(ipId), "Expected a valid CCNxInteresPayloadId.");
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/segment1/segment2/segment3");
+ ccnxName_Append(name, ccnxInterestPayloadId_GetNameSegment(ipId));
+
+ CCNxInterestPayloadId *result = ccnxInterestPayloadId_CreateFromSegmentInName(name);
+ ccnxName_Release(&name);
+
+ assertNotNull(result, "Should have found a payload ID");
+ ccnxInterestPayloadId_AssertValid(result);
+
+ assertTrue(ccnxInterestPayloadId_Equals(result, ipId),
+ "Expected source and result Interest Payload IDs to be equal");
+
+ ccnxInterestPayloadId_Release(&ipId);
+ ccnxInterestPayloadId_Release(&result);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_CreateFromSegmentInName_NotFound)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/segment1/segment2/segment3");
+ CCNxInterestPayloadId *result = ccnxInterestPayloadId_CreateFromSegmentInName(name);
+ ccnxName_Release(&name);
+
+ assertNull(result, "Should have not found a payload ID");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_Acquire)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t type = data->type;
+ PARCBuffer *value = parcBuffer_Acquire(data->value);
+ CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type);
+ parcBuffer_Release(&value);
+ ccnxInterestPayloadId_AssertValid(ipId);
+
+ CCNxInterestPayloadId *ipIdAcq = ccnxInterestPayloadId_Acquire(ipId);
+ ccnxInterestPayloadId_AssertValid(ipIdAcq);
+
+ ccnxInterestPayloadId_Release(&ipId);
+ ccnxInterestPayloadId_Release(&ipIdAcq);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_GetValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t type = data->type;
+ PARCBuffer *value = parcBuffer_Acquire(data->value);
+ CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type);
+ ccnxInterestPayloadId_AssertValid(ipId);
+
+ assertTrue(parcBuffer_Equals(ccnxInterestPayloadId_GetValue(ipId), value),
+ "Expect GetId to produce the correct result");
+
+ parcBuffer_Release(&value);
+ ccnxInterestPayloadId_Release(&ipId);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_GetType)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t type = data->type;
+ PARCBuffer *value = parcBuffer_Acquire(data->value);
+ CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type);
+ ccnxInterestPayloadId_AssertValid(ipId);
+
+ assertTrue(ccnxInterestPayloadId_GetType(ipId) == type,
+ "Expect GetId to produce the correct result");
+
+ parcBuffer_Release(&value);
+ ccnxInterestPayloadId_Release(&ipId);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_GetType_App)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t type = data->type;
+ PARCBuffer *value = parcBuffer_Acquire(data->value);
+ CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type);
+ ccnxInterestPayloadId_AssertValid(ipId);
+
+ assertTrue(parcBuffer_Equals(ccnxInterestPayloadId_GetValue(ipId), value),
+ "Expect GetId to produce the correct result");
+
+ parcBuffer_Release(&value);
+ ccnxInterestPayloadId_Release(&ipId);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_HashCode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t type = data->type;
+ PARCBuffer *value = parcBuffer_Acquire(data->value);
+ CCNxInterestPayloadId *ipId1 = ccnxInterestPayloadId_Create(value, type);
+ uint32_t hashCode1 = ccnxInterestPayloadId_HashCode(ipId1);
+ CCNxInterestPayloadId *ipId2 = ccnxInterestPayloadId_Create(value, type);
+ uint32_t hashCode2 = ccnxInterestPayloadId_HashCode(ipId2);
+ assertTrue(hashCode1 == hashCode2, "Expect hash codes of equal objects to be equal");
+ parcBuffer_Release(&value);
+ ccnxInterestPayloadId_Release(&ipId1);
+ ccnxInterestPayloadId_Release(&ipId2);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_Equals)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t type = data->type;
+ PARCBuffer *value = parcBuffer_WrapCString("123456789abcdef");
+ CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type);
+ ccnxInterestPayloadId_AssertValid(ipId);
+
+ PARCBuffer *value2 = parcBuffer_WrapCString("123456789abcdef");
+ CCNxInterestPayloadId *ipId2 = ccnxInterestPayloadId_Create(value2, type);
+ ccnxInterestPayloadId_AssertValid(ipId2);
+
+ assertTrue(ccnxInterestPayloadId_Equals(ipId, ipId2),
+ "Expect InterestPayloadIds to be equal");
+
+ CCNxInterestPayloadId *ipId3 = ccnxInterestPayloadId_Create(value, type);
+ ccnxInterestPayloadId_AssertValid(ipId3);
+
+ assertTrue(ccnxInterestPayloadId_Equals(ipId, ipId3),
+ "Expect InterestPayloadIds to be equal");
+
+ parcBuffer_Release(&value);
+ parcBuffer_Release(&value2);
+ ccnxInterestPayloadId_Release(&ipId);
+ ccnxInterestPayloadId_Release(&ipId2);
+ ccnxInterestPayloadId_Release(&ipId3);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_NotEquals)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t type = data->type;
+ PARCBuffer *value = parcBuffer_WrapCString("123456789abcdef");
+ CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type);
+ ccnxInterestPayloadId_AssertValid(ipId);
+
+ PARCBuffer *value2 = parcBuffer_WrapCString("123456789abcdex");
+ CCNxInterestPayloadId *ipId2 = ccnxInterestPayloadId_Create(value2, type);
+ ccnxInterestPayloadId_AssertValid(ipId2);
+
+ assertTrue(!ccnxInterestPayloadId_Equals(ipId, ipId2),
+ "Expect InterestPayloadIds to be equal");
+
+ parcBuffer_Release(&value);
+ parcBuffer_Release(&value2);
+ ccnxInterestPayloadId_Release(&ipId);
+ ccnxInterestPayloadId_Release(&ipId2);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_Compare)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t type = data->type;
+ PARCBuffer *value1 = parcBuffer_WrapCString("123456789abcdef");
+ CCNxInterestPayloadId *ipId1 = ccnxInterestPayloadId_Create(value1, type);
+ ccnxInterestPayloadId_AssertValid(ipId1);
+
+ assertTrue(ccnxInterestPayloadId_Compare(ipId1, ipId1) == 0,
+ "Expect compare result of 0 when comparing InterestPayloadId to itself");
+
+ PARCBuffer *value1p = parcBuffer_WrapCString("123456789abcdef");
+ CCNxInterestPayloadId *ipId1p = ccnxInterestPayloadId_Create(value1p, type);
+ ccnxInterestPayloadId_AssertValid(ipId1p);
+
+ assertTrue(ccnxInterestPayloadId_Compare(ipId1, ipId1p) == 0,
+ "Expect compare result of 0 when comparing InterestPayloadIds with the same content");
+
+ PARCBuffer *value2 = parcBuffer_WrapCString("123456789abcdex");
+ CCNxInterestPayloadId *ipId2 = ccnxInterestPayloadId_Create(value2, type);
+ ccnxInterestPayloadId_AssertValid(ipId2);
+
+ assertTrue(ccnxInterestPayloadId_Compare(ipId2, ipId1) > 0,
+ "Expect compare result > 0 when comparing InterestPayloadId2 to InterestPayloadId1");
+
+ parcBuffer_Release(&value1);
+ parcBuffer_Release(&value1p);
+ parcBuffer_Release(&value2);
+
+ ccnxInterestPayloadId_Release(&ipId1);
+ ccnxInterestPayloadId_Release(&ipId1p);
+ ccnxInterestPayloadId_Release(&ipId2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_Copy)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t type = data->type;
+ PARCBuffer *value1 = parcBuffer_Acquire(data->value);
+ CCNxInterestPayloadId *ipId1 = ccnxInterestPayloadId_Create(value1, type);
+ parcBuffer_Release(&value1);
+ ccnxInterestPayloadId_AssertValid(ipId1);
+
+ CCNxInterestPayloadId *ipIdCopy = ccnxInterestPayloadId_Copy(ipId1);
+ ccnxInterestPayloadId_AssertValid(ipIdCopy);
+ assertTrue(ccnxInterestPayloadId_Equals(ipId1, ipIdCopy), "Expect original and copy InterestPayloadId to be equal");
+
+ ccnxInterestPayloadId_Release(&ipId1);
+ ccnxInterestPayloadId_Release(&ipIdCopy);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_IsValid)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t type = data->type;
+ PARCBuffer *value = parcBuffer_Acquire(data->value);
+ CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type);
+ parcBuffer_Release(&value);
+
+ assertTrue(ccnxInterestPayloadId_IsValid(ipId), "Expected a valid CCNxInteresPayloadId.");
+ ccnxInterestPayloadId_Release(&ipId);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_ToString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t type = data->type;
+ char *test = "123456789abcdef";
+ PARCBuffer *value = parcBuffer_WrapCString(test);
+ CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type);
+ parcBuffer_Release(&value);
+
+ char *result = ccnxInterestPayloadId_ToString(ipId);
+ assertNotNull(result, "Expect a non-NULL result from ToString");
+ ccnxInterestPayloadId_Release(&ipId);
+
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(10);
+ parcBufferComposer_PutString(composer, CCNxNameLabel_InterestPayloadId);
+ parcBufferComposer_PutChar(composer, '=');
+
+ PARCBufferComposer *uriComposer = parcBufferComposer_Allocate(10);
+ parcBufferComposer_PutChar(uriComposer, type);
+ parcBufferComposer_PutString(uriComposer, test);
+ PARCBuffer *producedBuffer = parcBufferComposer_ProduceBuffer(uriComposer);
+ PARCURISegment *uriSegment = parcURISegment_CreateFromBuffer(producedBuffer);
+ parcBuffer_Release(&producedBuffer);
+ parcBufferComposer_Release(&uriComposer);
+ parcURISegment_BuildString(uriSegment, composer);
+ parcURISegment_Release(&uriSegment);
+ char *expect = parcBufferComposer_ToString(composer);
+ parcBufferComposer_Release(&composer);
+
+ assertTrue(strcmp(expect, result) == 0, "Expect test and result strings to be the same.");
+
+ parcMemory_Deallocate((void **) &result);
+ parcMemory_Deallocate((void **) &expect);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_GetNameSegment)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint8_t type = data->type;
+ PARCBuffer *value = parcBuffer_Acquire(data->value);
+ CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type);
+
+ CCNxNameSegment *segment = ccnxNameSegment_Acquire(ccnxInterestPayloadId_GetNameSegment(ipId));
+ ccnxInterestPayloadId_Release(&ipId);
+
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(parcBuffer_Capacity(value) + 1);
+ parcBufferComposer_PutUint8(composer, type);
+ parcBufferComposer_PutBuffer(composer, value);
+ PARCBuffer *testValue = parcBufferComposer_ProduceBuffer(composer);
+ parcBufferComposer_Release(&composer);
+ parcBuffer_Release(&value);
+ CCNxNameSegment *testSegment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_PAYLOADID, testValue);
+ parcBuffer_Release(&testValue);
+ assertTrue(ccnxNameSegment_Equals(segment, testSegment), "Expect GetAsNameSegment result to match test NameSegment");
+
+ ccnxNameSegment_Release(&segment);
+ ccnxNameSegment_Release(&testSegment);
+}
+
+LONGBOW_TEST_FIXTURE(Error)
+{
+ LONGBOW_RUN_TEST_CASE(Error, ccnxInterestPayloadId__CreateFromNameSegment_NotFound);
+}
+
+typedef struct {
+ CCNxName *name;
+} TestDataError;
+
+LONGBOW_TEST_FIXTURE_SETUP(Error)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+
+ TestDataError *data = parcMemory_AllocateAndClear(sizeof(TestDataError));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataError));
+ data->name = ccnxName_CreateFromCString("lci:/segment1/segment2/segment3");
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Error)
+{
+ TestDataError *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxName_Release(&data->name);
+ parcMemory_Deallocate((void **) &data);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ parcMemory_SetInterface(_originalMemoryProvider);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Error, ccnxInterestPayloadId__CreateFromNameSegment_NotFound, .event = &LongBowAssertEvent)
+{
+ TestDataError *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxNameSegment *nameSegment = ccnxName_GetSegment(data->name, 0);
+ CCNxInterestPayloadId *result =
+ _ccnxInterestPayloadId_CreateFromNameSegment(nameSegment);
+ assertNull(result, "Expect an assert event or NULL");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_InterestPayloadId);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_InterestReturn.c b/libccnx-common/ccnx/common/test/test_ccnx_InterestReturn.c
new file mode 100755
index 00000000..79e27994
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_InterestReturn.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_InterestReturn.c"
+#include "../ccnx_Interest.h"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/common/ccnx_Interest.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+#include <ccnx/common/ccnx_PayloadType.h>
+
+typedef struct test_data {
+ CCNxTlvDictionary *interest;
+ CCNxInterestInterface *interestImpl;
+
+ CCNxName *name;
+ PARCBuffer *keyid;
+ PARCBuffer *contentObjectHash;
+ PARCBuffer *payload;
+
+ // allocated data
+ uint8_t keyidArray[32];
+ uint8_t contentObjectHashArray[32];
+ uint8_t payloadArray[128];
+
+ uint32_t lifetime;
+ uint32_t hoplimit;
+ CCNxPayloadType payloadType;
+} TestData;
+
+
+LONGBOW_TEST_RUNNER(ccnx_InterestReturnV1)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_InterestReturnV1)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_InterestReturnV1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ========================================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_Create);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_GetReturnCode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_NotEquals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_GetInterestFields);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%lu) returned NULL", sizeof(TestData));
+ data->name = ccnxName_CreateFromCString("lci:/once/upon/a/time");
+
+ for (int i = 0; i < 32; i++) {
+ data->keyidArray[i] = i * 7;
+ data->contentObjectHashArray[i] = i * 11;
+ }
+
+ for (int i = 0; i < 128; i++) {
+ data->payloadArray[i] = i * 13;
+ }
+
+ data->interestImpl = &CCNxInterestFacadeV1_Implementation;
+ data->keyid = parcBuffer_Wrap(data->keyidArray, 32, 0, 32);
+ data->contentObjectHash = parcBuffer_Wrap(data->contentObjectHashArray, 32, 0, 32);
+ data->payloadType = CCNxPayloadType_DATA;
+ data->payload = parcBuffer_Wrap(data->payloadArray, 128, 0, 128);
+
+ data->lifetime = 900;
+ data->hoplimit = 77;
+
+ data->interest = ccnxInterest_CreateWithImpl(data->interestImpl,
+ data->name,
+ data->lifetime,
+ data->keyid,
+ data->contentObjectHash,
+ data->hoplimit);
+
+ ccnxInterest_SetPayload(data->interest, data->payload);
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxName_Release(&data->name);
+ parcBuffer_Release(&data->keyid);
+ parcBuffer_Release(&data->contentObjectHash);
+ parcBuffer_Release(&data->payload);
+ ccnxTlvDictionary_Release(&data->interest);
+
+ parcMemory_Deallocate((void **) &data);
+
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_TEARDOWN_FAILED;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_Create)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxInterestReturn *interestReturn =
+ ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute);
+
+ ccnxInterestReturn_AssertValid(interestReturn);
+
+ //assertTrue(ccnxInterestReturn_IsValid(interestReturn), "InterestReturn is not valid");
+ ccnxTlvDictionary_Release(&interestReturn);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_AcquireRelease)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxInterestReturn *interestReturn =
+ ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute);
+
+ assertNotNull(interestReturn, "Expect non-NULL interestReturn");
+
+ CCNxInterestReturn *testInterestReturn = ccnxInterestReturn_Acquire(interestReturn);
+ assertNotNull(testInterestReturn, "Expected a non-NULL testInterestReturn");
+
+ ccnxInterestReturn_Release(&testInterestReturn);
+ assertNull(testInterestReturn, "Expected a NULL testInterestReturn");
+
+ ccnxInterestReturn_Release(&interestReturn);
+ assertNull(interestReturn, "Expected a NULL testInterestReturn");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_Equals)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxInterestReturn *interestReturn =
+ ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute);
+ assertTrue(ccnxInterestReturn_Equals(interestReturn, interestReturn), "Expect same interestReturn pointers to be equal");
+
+ CCNxInterestReturn *acquiredIR = ccnxInterestReturn_Acquire(interestReturn);
+ assertTrue(ccnxInterestReturn_Equals(interestReturn, acquiredIR), "Expect acquired interestReturn to be equal to original");
+ ccnxInterestReturn_Release(&acquiredIR);
+
+ CCNxInterestReturn *identicalIR =
+ ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute);
+ assertTrue(ccnxInterestReturn_Equals(interestReturn, identicalIR), "Expect identical interestReturn to be equal to original");
+
+ ccnxInterestReturn_Release(&identicalIR);
+ ccnxInterestReturn_Release(&interestReturn);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_NotEquals)
+{
+ assertFalse(ccnxInterestReturn_Equals(NULL, NULL), "Expect two NULL interests to not be equal");
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxInterestReturn *interestReturn =
+ ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute);
+ assertFalse(ccnxInterestReturn_Equals(interestReturn, NULL), "Expect a NULL interest to not be equal");
+
+ CCNxInterestReturn *testIR =
+ ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_MTUTooLarge);
+ assertFalse(ccnxInterestReturn_Equals(interestReturn, testIR), "Expect interestReturn's with different return codes to be !=");
+
+ ccnxInterestReturn_Release(&testIR);
+ ccnxInterestReturn_Release(&interestReturn);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_ToString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxInterestReturn *interestReturn =
+ ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute);
+
+ const char *string = ccnxInterestReturn_ToString(interestReturn);
+ assertNotNull(string, "Expected non-null result from ccnxInterestReturn_ToString.");
+
+ parcMemory_Deallocate((void **) &string);
+
+ ccnxInterestReturn_Release(&interestReturn);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_GetReturnCode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxInterestReturn *interestReturn =
+ ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute);
+
+ CCNxInterestReturn_ReturnCode code =
+ ccnxInterestReturn_GetReturnCode(interestReturn);
+
+ assertTrue((CCNxInterestReturn_ReturnCode_NoRoute == code), "InterestReturn wrong Return Code");
+ ccnxInterestReturn_Release(&interestReturn);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_GetInterestFields)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxInterestReturn *interestReturn =
+ ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute);
+
+ CCNxName *name = ccnxInterest_GetName(interestReturn);
+ assertTrue(ccnxName_Equals(name, data->name), "Names do not match")
+ {
+ printf("\ngot : \n"); ccnxName_Display(name, 3);
+ printf("\nexpected: \n"); ccnxName_Display(data->name, 3);
+ }
+
+ uint32_t hopLimit = ccnxInterest_GetHopLimit(interestReturn);
+ assertTrue(hopLimit == data->hoplimit, "Wrong hoplimit: got %u expected %u", hopLimit, data->hoplimit);
+
+ uint32_t lifetime = (uint32_t) ccnxInterest_GetLifetime(interestReturn);
+ assertTrue(lifetime == data->lifetime, "Wrong lifetime: got %u expected %u", lifetime, data->lifetime);
+
+ PARCBuffer *buff = ccnxInterest_GetKeyIdRestriction(interestReturn);
+ assertTrue(parcBuffer_Equals(buff, data->keyid), "KeyIDs do not match")
+ {
+ printf("\ngot : \n"); parcBuffer_Display(buff, 3);
+ printf("\nexpected: \n"); parcBuffer_Display(data->keyid, 3);
+ }
+
+ buff = ccnxInterest_GetPayload(interestReturn);
+ assertTrue(parcBuffer_Equals(buff, data->payload), "Payloads do not match")
+ {
+ printf("\ngot : \n"); parcBuffer_Display(buff, 3);
+ printf("\nexpected: \n"); parcBuffer_Display(data->payload, 3);
+ }
+
+ ccnxInterestReturn_Release(&interestReturn);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_InterestReturnV1);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_Key.c b/libccnx-common/ccnx/common/test/test_ccnx_Key.c
new file mode 100755
index 00000000..c1bd5ed2
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_Key.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include "../ccnx_Key.c"
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(ccnx_Key)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(ccnx_Key)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_Key)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKey_CreateRelease);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKey_CreateFromHexString);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKey_FromByteBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKey_ToString);
+}
+
+typedef struct {
+ char *hexString;
+} TestData;
+
+static TestData*
+commonSetup()
+{
+ char *hexString = "30819F300D06092A864886F70D010101050003818D0030818902818100A826C09E01FF4970428213C96312B46050514FD5F87E670A4784C75D8B23CD073B1CBEF328E538584E442A769DF77299192BCF3603F50F14C5664994250E5C24DF47B86EA5C7CA99B3584E9A63BC5993569FF3612C71AD46A088CDC7346B9BE021D4CA1764CF5434F993E6120363C551E2979BDB3F0345B4994BCED9CB260EEB0203010001";
+
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->hexString = parcMemory_StringDuplicate(hexString, strlen(hexString));
+ return data;
+}
+
+static void
+commonTearDown(TestData *data)
+{
+ parcMemory_Deallocate((void **) &(data->hexString));
+ parcMemory_Deallocate((void **) &data);
+}
+
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ TestData *data = commonSetup();
+ longBowTestCase_SetClipBoardData(testCase, data);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ commonTearDown(data);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxKey_FromByteBuffer)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCBuffer *hexBuf = parcBuffer_ParseHexString(data->hexString);
+ CCNxKey *key = ccnxKey_Create(hexBuf);
+ parcBuffer_Release(&hexBuf);
+ ccnxKey_Release(&key);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKey_CreateRelease)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxKey *key = ccnxKey_CreateFromHexString(data->hexString);
+ ccnxKey_AssertValid(key);
+
+ char *string = ccnxKey_ToString(key);
+
+ ccnxKey_Release(&key);
+ assertNull(key, "Key was not nulled out after Release()");
+
+ parcMemory_Deallocate((void **) &string);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKey_CreateFromHexString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxKey *key = ccnxKey_CreateFromHexString(data->hexString);
+ ccnxKey_AssertValid(key);
+
+ char *string = ccnxKey_ToHexString(key);
+
+ assertTrue(strcasecmp(data->hexString, string) == 0,
+ "Expected '%s' actual '%s'", data->hexString, string);
+
+ ccnxKey_Release(&key);
+ assertNull(key, "Key was not nulled out after Release()");
+
+ parcMemory_Deallocate((void **) &string);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKey_ToString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxKey *key = ccnxKey_CreateFromHexString(data->hexString);
+ ccnxKey_AssertValid(key);
+
+ char *string = ccnxKey_ToString(key);
+
+ ccnxKey_Release(&key);
+ assertNull(key, "Key was not nulled out after Release()");
+
+ parcMemory_Deallocate((void **) &string);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_Key);
+ exit(longBowMain(argc, argv, testRunner, NULL));
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_KeyLocator.c b/libccnx-common/ccnx/common/test/test_ccnx_KeyLocator.c
new file mode 100755
index 00000000..3e877179
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_KeyLocator.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_KeyLocator.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(ccnx_KeyLocator)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_KeyLocator)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_KeyLocator)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_FromKey);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_FromKeyLink);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_GetKey);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_GetKeyName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_GetType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_IsKey);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_IsKeyName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKeyLocator_Copy)
+{
+ CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name");
+ CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL);
+ CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink);
+
+ ccnxKeyLocator_AssertValid(keyLocator);
+
+ CCNxKeyLocator *copy = ccnxKeyLocator_Copy(keyLocator);
+ assertTrue(ccnxKeyLocator_Equals(copy, keyLocator), "Expected orig and copy to be the same");
+
+ ccnxKeyLocator_Release(&keyLocator);
+ ccnxKeyLocator_Release(&copy);
+
+ ccnxName_Release(&keyURIName);
+ ccnxLink_Release(&keyLink);
+
+ // Try FromHexString, too, for yucks.
+ PARCBuffer *keyBuffer = parcBuffer_WrapCString("hello world");
+ PARCKeyId *keyId = parcKeyId_Create(keyBuffer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, keyBuffer);
+ parcKeyId_Release(&keyId);
+ parcBuffer_Release(&keyBuffer);
+ CCNxKeyLocator *keyLocator2 = ccnxKeyLocator_CreateFromKey(key);
+
+ CCNxKeyLocator *copy2 = ccnxKeyLocator_Copy(keyLocator2);
+ assertTrue(ccnxKeyLocator_Equals(copy, keyLocator), "Expected orig and copy to be the same");
+
+ parcKey_Release(&key);
+ ccnxKeyLocator_Release(&keyLocator2);
+ ccnxKeyLocator_Release(&copy2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKeyLocator_Destroy)
+{
+ CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name");
+ CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL);
+ CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink);
+
+ ccnxKeyLocator_AssertValid(keyLocator);
+
+ ccnxKeyLocator_Release(&keyLocator);
+ assertNull(keyLocator, "keyLocator was not nulled out by Release()");
+
+ ccnxLink_Release(&keyLink);
+ ccnxName_Release(&keyURIName);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKeyLocator_Equals)
+{
+ char *hexString = "ABCDEF1234";
+ PARCBuffer *keyBuffer = parcBuffer_WrapCString(hexString);
+ PARCKeyId *keyId = parcKeyId_Create(keyBuffer);
+ PARCKey *key1 = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, keyBuffer);
+ CCNxKeyLocator *keyLocator1 = ccnxKeyLocator_CreateFromKey(key1);
+ parcKeyId_Release(&keyId);
+ parcBuffer_Release(&keyBuffer);
+
+ CCNxKeyLocator *keyLocator1Copy = ccnxKeyLocator_Copy(keyLocator1);
+
+ PARCBuffer *keyBuffer2 = parcBuffer_WrapCString(hexString);
+ PARCKeyId *keyId2 = parcKeyId_Create(keyBuffer2);
+ PARCKey *key2 = parcKey_CreateFromDerEncodedPublicKey(keyId2, PARCSigningAlgorithm_RSA, keyBuffer2);
+ CCNxKeyLocator *keyLocator2 = ccnxKeyLocator_CreateFromKey(key2);
+ parcBuffer_Release(&keyBuffer2);
+ parcKeyId_Release(&keyId2);
+
+ CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name");
+ CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL);
+ CCNxKeyLocator *keyLocatorDiff = ccnxKeyLocator_CreateFromKeyLink(keyLink);
+
+ ccnxKeyLocator_AssertValid(keyLocator1);
+ ccnxKeyLocator_AssertValid(keyLocator1Copy);
+ ccnxKeyLocator_AssertValid(keyLocator2);
+ ccnxKeyLocator_AssertValid(keyLocatorDiff);
+
+ assertEqualsContract(ccnxKeyLocator_Equals, keyLocator1, keyLocator1Copy, keyLocator2, keyLocatorDiff);
+
+ parcKey_Release(&key1);
+ ccnxKeyLocator_Release(&keyLocator1);
+ ccnxKeyLocator_Release(&keyLocator1Copy);
+
+ parcKey_Release(&key2);
+ ccnxKeyLocator_Release(&keyLocator2);
+
+ ccnxName_Release(&keyURIName);
+ ccnxLink_Release(&keyLink);
+ ccnxKeyLocator_Release(&keyLocatorDiff);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKeyLocator_FromKey)
+{
+ char *hexString = "ABCDEF1234";
+ PARCBuffer *keyBuffer = parcBuffer_WrapCString(hexString);
+ PARCKeyId *keyId = parcKeyId_Create(keyBuffer);
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, keyBuffer);
+ CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKey(key);
+ parcKeyId_Release(&keyId);
+ parcBuffer_Release(&keyBuffer);
+
+ ccnxKeyLocator_AssertValid(keyLocator);
+
+ ccnxKeyLocator_Release(&keyLocator);
+ parcKey_Release(&key);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKeyLocator_FromKeyLink)
+{
+ CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name");
+ CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL);
+ CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink);
+
+ ccnxKeyLocator_AssertValid(keyLocator);
+
+ ccnxKeyLocator_Release(&keyLocator);
+ ccnxName_Release(&keyURIName);
+ ccnxLink_Release(&keyLink);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKeyLocator_GetKey)
+{
+ char *hexString = "ABCDEF1234";
+ PARCBuffer *keyBuffer = parcBuffer_WrapCString(hexString);
+ PARCKeyId *keyId = parcKeyId_Create(keyBuffer);
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, keyBuffer);
+ CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKey(key);
+
+ parcKeyId_Release(&keyId);
+ parcBuffer_Release(&keyBuffer);
+
+ ccnxKeyLocator_AssertValid(keyLocator);
+ PARCKey *actual = ccnxKeyLocator_GetKey(keyLocator);
+ assertTrue(actual == key, "Actual certificate didn't match expected");
+
+ ccnxKeyLocator_Release(&keyLocator);
+ parcKey_Release(&key);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKeyLocator_GetKeyName)
+{
+ CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name/test");
+ CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL);
+ CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink);
+
+ ccnxKeyLocator_AssertValid(keyLocator);
+ const CCNxName *actual = ccnxLink_GetName(ccnxKeyLocator_GetKeyLink(keyLocator));
+ assertTrue(ccnxName_Equals(actual, keyURIName), "Actual keyName did not match the one returned by GetKeyName()");
+
+ ccnxKeyLocator_Release(&keyLocator);
+ ccnxName_Release(&keyURIName);
+ ccnxLink_Release(&keyLink);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKeyLocator_GetType)
+{
+ // Try FromKey
+ char *hexString = "ABCDEF1234";
+ PARCBuffer *keyBuffer = parcBuffer_WrapCString(hexString);
+ PARCKeyId *keyId = parcKeyId_Create(keyBuffer);
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, keyBuffer);
+ CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKey(key);
+ parcKeyId_Release(&keyId);
+ parcBuffer_Release(&keyBuffer);
+
+ ccnxKeyLocator_AssertValid(keyLocator);
+ assertTrue(ccnxKeyLocator_GetType(keyLocator) == CCNxKeyLocatorType_Key, "Actual certificate type didn't match expected type");
+
+ ccnxKeyLocator_Release(&keyLocator);
+ parcKey_Release(&key);
+
+ // Try KeyName
+ CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name/test");
+ CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL);
+ keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink);
+
+ ccnxKeyLocator_AssertValid(keyLocator);
+ assertTrue(ccnxKeyLocator_GetType(keyLocator) == CCNxKeyLocatorType_Link, "Actual certificate type didn't match expected type");
+ assertFalse(ccnxKeyLocator_GetType(keyLocator) == CCNxKeyLocatorType_Key, "Actual certificate type didn't match expected type");
+
+ ccnxKeyLocator_Release(&keyLocator);
+ ccnxName_Release(&keyURIName);
+ ccnxLink_Release(&keyLink);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKeyLocator_IsKey)
+{
+ char *hexString = "ABCDEF1234";
+ PARCBuffer *keyBuffer = parcBuffer_WrapCString(hexString);
+ PARCKeyId *keyId = parcKeyId_Create(keyBuffer);
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, keyBuffer);
+ CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKey(key);
+ parcKeyId_Release(&keyId);
+ parcBuffer_Release(&keyBuffer);
+
+ ccnxKeyLocator_AssertValid(keyLocator);
+ assertTrue(ccnxKeyLocator_IsKey(keyLocator), "Expected Iskey to be true");
+ assertFalse(ccnxKeyLocator_IsKeyLink(keyLocator), "Expected IsKeyLink to be false");
+
+ ccnxKeyLocator_Release(&keyLocator);
+ parcKey_Release(&key);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKeyLocator_IsKeyName)
+{
+ CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name/test");
+ CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL);
+ CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink);
+
+ ccnxKeyLocator_AssertValid(keyLocator);
+ assertFalse(ccnxKeyLocator_IsKey(keyLocator), "Expected Iskey to be false");
+ assertTrue(ccnxKeyLocator_IsKeyLink(keyLocator), "Expected IsKeyLink to be true");
+
+ ccnxKeyLocator_Release(&keyLocator);
+ ccnxName_Release(&keyURIName);
+ ccnxLink_Release(&keyLink);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxKeyLocator_ToString)
+{
+ CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name/test");
+ CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL);
+ CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink);
+
+ ccnxKeyLocator_AssertValid(keyLocator);
+
+ char *actualString = ccnxKeyLocator_ToString(keyLocator);
+
+ assertTrue(0 == strncmp("KeyLocator", actualString, strlen("KeyLocator")), "ToString() did not return the expected prefix");
+
+ parcMemory_Deallocate((void **) &actualString);
+
+ ccnxLink_Release(&keyLink);
+ ccnxName_Release(&keyURIName);
+ ccnxKeyLocator_Release(&keyLocator);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, ccnxKeyLocator_Create);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, ccnxKeyLocator_Create)
+{
+ CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name");
+ CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL);
+ CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink);
+
+ ccnxKeyLocator_AssertValid(keyLocator);
+
+ ccnxKeyLocator_Release(&keyLocator);
+ ccnxName_Release(&keyURIName);
+ ccnxLink_Release(&keyLink);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_KeyLocator);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_KeystoreUtilities.c b/libccnx-common/ccnx/common/test/test_ccnx_KeystoreUtilities.c
new file mode 100644
index 00000000..0ab770a5
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_KeystoreUtilities.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_KeystoreUtilities.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+
+#include <errno.h>
+#include <ftw.h>
+
+typedef struct test_data {
+ char dirname[1024];
+} TestData;
+
+static int
+deleteEntry(const char *fpath, const struct stat *sb,
+ int tflag, struct FTW *ftwbuf)
+{
+ if (tflag == FTW_DP) {
+ // directory in post-order
+ rmdir(fpath);
+ } else {
+ unlink(fpath);
+ }
+ return 0; /* To tell nftw() to continue */
+}
+
+__attribute__((unused))
+static void
+recursiveDelete(const char *path)
+{
+ // only allow under tmp
+ assertTrue(strncmp(path, "/tmp/", 5) == 0, "Path must begin with /tmp/: %s", path);
+ // dont allow ".."
+ assertNull(strstr(path, ".."), "Path cannot have .. in it: %s", path);
+
+ // depth first, dont't follow symlinks
+ int flags = FTW_DEPTH | FTW_PHYS;
+
+ // maximum 20 fds open at a time
+ int max_fd = 20;
+
+ int failure = nftw(path, deleteEntry, max_fd, flags);
+ assertFalse(failure, "Error on recursive delete: (%d) %s", errno, strerror(errno));
+}
+
+static TestData *
+commonSetup(const char *testCaseName)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ sprintf(data->dirname, "/tmp/%s.%d", testCaseName, getpid());
+ mkdir(data->dirname, S_IRWXU | S_IRWXG);
+ setenv("HOME", data->dirname, 1);
+
+ return data;
+}
+
+static void
+commonTeardown(TestData **dataPtr)
+{
+ TestData *data = *dataPtr;
+
+ recursiveDelete(data->dirname);
+ parcMemory_Deallocate((void **) &data);
+ *dataPtr = NULL;
+}
+
+LONGBOW_TEST_RUNNER(ccnx_KeystoreUtilities)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_KeystoreUtilities)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_KeystoreUtilities)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ TestData *data = commonSetup(longBowTestCase_GetName(testCase));
+ longBowTestCase_SetClipBoardData(testCase, data);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ commonTeardown(&data);
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, ccnxKeystoreUtilities_ConstructPath);
+ LONGBOW_RUN_TEST_CASE(Local, ccnxKeystoreUtilities_HomeDirectoryFromEnv);
+ LONGBOW_RUN_TEST_CASE(Local, ccnxKeystoreUtilities_HomeDirectoryFromPasswd);
+
+ LONGBOW_RUN_TEST_CASE(Local, ccnxKeystoreUtilities_OpenFromHomeDirectory_Missing);
+
+ LONGBOW_RUN_TEST_CASE(Local, ccnxKeystoreUtilities_OpenFromHomeDirectory_Newfile);
+ LONGBOW_RUN_TEST_CASE(Local, ccnxKeystoreUtilities_OpenFromHomeDirectory_Oldfile);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ parcSecurity_Init();
+
+ TestData *data = commonSetup(longBowTestCase_GetName(testCase));
+ longBowTestCase_SetClipBoardData(testCase, data);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ commonTeardown(&data);
+
+ parcSecurity_Fini();
+
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, ccnxKeystoreUtilities_ConstructPath)
+{
+ const char *dir = "/some/where";
+ const char *file = "else";
+ const char *truth = "/some/where/else";
+
+ char *test = ccnxKeystoreUtilities_ConstructPath(dir, file);
+ assertTrue(strcmp(truth, test) == 0, "Wrong path, expected %s got %s", truth, test);
+ parcMemory_Deallocate((void **) &test);
+}
+
+LONGBOW_TEST_CASE(Local, ccnxKeystoreUtilities_HomeDirectoryFromEnv)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ char *dir = ccnxKeystoreUtilities_HomeDirectoryFromEnv();
+ assertNotNull(dir, "Did not get HOME variable from environment");
+ assertTrue(strcmp(dir, data->dirname) == 0, "HOME directory not correct, expecting %s got %s\n", data->dirname, dir);
+ parcMemory_Deallocate((void **) &dir);
+}
+
+LONGBOW_TEST_CASE(Local, ccnxKeystoreUtilities_HomeDirectoryFromPasswd)
+{
+ char *dir = ccnxKeystoreUtilities_HomeDirectoryFromPasswd();
+ assertNotNull(dir, "Did not get HOME variable from environment");
+ parcMemory_Deallocate((void **) &dir);
+}
+
+/**
+ * Create a temporary directory, set HOME to it, then try to open, but do
+ * not create the keystore. should return NULL.
+ */
+LONGBOW_TEST_CASE(Local, ccnxKeystoreUtilities_OpenFromHomeDirectory_Missing)
+{
+ KeystoreParams *params = ccnxKeystoreUtilities_OpenFromHomeDirectory("abcd");
+ assertNull(params, "Signer should have been null opening from non-existent keystore");
+}
+
+
+/**
+ * Create a keystore with the old default name in the old location
+ */
+LONGBOW_TEST_CASE(Local, ccnxKeystoreUtilities_OpenFromHomeDirectory_Oldfile)
+{
+ char *homedir = ccnxKeystoreUtilities_GetHomeDirectory();
+ char *ccnxdir = ccnxKeystoreUtilities_ConstructPath(homedir, ".ccnx");
+ mkdir(ccnxdir, 0700);
+ char *path = ccnxKeystoreUtilities_ConstructPath(ccnxdir, ".ccnx_keystore");
+
+ bool success = parcPkcs12KeyStore_CreateFile(path, "1234", "ccnxuser", 1024, 365);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile() failed.");
+
+ KeystoreParams *signer = ccnxKeystoreUtilities_OpenFromHomeDirectory("1234");
+ assertNotNull(signer, "Signer should be non-null opening from a file we just created");
+ keystoreParams_Destroy(&signer);
+
+ parcMemory_Deallocate((void **) &path);
+ parcMemory_Deallocate((void **) &ccnxdir);
+ parcMemory_Deallocate((void **) &homedir);
+}
+
+/**
+ * Create a keystore with the new default name in the old location
+ */
+LONGBOW_TEST_CASE(Local, ccnxKeystoreUtilities_OpenFromHomeDirectory_Newfile)
+{
+ char *homedir = ccnxKeystoreUtilities_GetHomeDirectory();
+ char *ccnxdir = ccnxKeystoreUtilities_ConstructPath(homedir, ".ccnx");
+ mkdir(ccnxdir, 0700);
+ char *path = ccnxKeystoreUtilities_ConstructPath(ccnxdir, ".ccnx_keystore.p12");
+
+ bool success = parcPkcs12KeyStore_CreateFile(path, "1234", "ccnxuser", 1024, 365);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile() failed.");
+
+ KeystoreParams *signer = ccnxKeystoreUtilities_OpenFromHomeDirectory("1234");
+ assertNotNull(signer, "Signer should be non-null opening from a file we just created");
+ keystoreParams_Destroy(&signer);
+
+ parcMemory_Deallocate((void **) &path);
+ parcMemory_Deallocate((void **) &ccnxdir);
+ parcMemory_Deallocate((void **) &homedir);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_KeystoreUtilities);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_Link.c b/libccnx-common/ccnx/common/test/test_ccnx_Link.c
new file mode 100755
index 00000000..87105468
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_Link.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+#include <ccnx/common/ccnx_Link.c>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(ccnx_Link)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_Link)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_Link)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxLink_Create_Full);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxLink_Create_EmptyKeyID);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxLink_Create_EmptyContentObjectHash);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxLink_Create_EmptyBoth);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxLink_AcquireRelease);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxLink_GetName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxLink_GetKeyID);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxLink_GetContentObjectHash);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxLink_Create_ToString);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxLink_Equals);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxLink_Create_Full)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ PARCBuffer *keyId = parcBuffer_Allocate(10);
+ PARCBuffer *contentObjectHash = parcBuffer_Allocate(10);
+
+ CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash);
+
+ assertNotNull(object, "Expected non-null return value.");
+
+ ccnxLink_Release(&object);
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&keyId);
+ parcBuffer_Release(&contentObjectHash);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxLink_Create_EmptyKeyID)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ PARCBuffer *keyId = NULL;
+ PARCBuffer *contentObjectHash = parcBuffer_Allocate(10);
+
+ CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash);
+
+ assertNotNull(object, "Expected non-null return value.");
+
+ ccnxLink_Release(&object);
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&contentObjectHash);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxLink_Create_EmptyContentObjectHash)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ PARCBuffer *keyId = parcBuffer_Allocate(10);
+ PARCBuffer *contentObjectHash = NULL;
+
+ CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash);
+
+ assertNotNull(object, "Expected non-null return value.");
+
+ ccnxLink_Release(&object);
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&keyId);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxLink_Create_EmptyBoth)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ PARCBuffer *keyId = NULL;
+ PARCBuffer *contentObjectHash = NULL;
+
+ CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash);
+
+ assertNotNull(object, "Expected non-null return value.");
+
+ ccnxLink_Release(&object);
+
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxLink_AcquireRelease)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ PARCBuffer *keyId = parcBuffer_Allocate(10);
+ PARCBuffer *contentObjectHash = parcBuffer_Allocate(10);
+
+ CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash);
+ parcObjectTesting_AssertAcquireReleaseContract(ccnxLink_Acquire, object);
+
+ ccnxLink_Release(&object);
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&keyId);
+ parcBuffer_Release(&contentObjectHash);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxLink_GetName)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ PARCBuffer *keyId = parcBuffer_Allocate(10);
+ PARCBuffer *contentObjectHash = parcBuffer_Allocate(10);
+
+ CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash);
+
+ const CCNxName *actualName = ccnxLink_GetName(object);
+ assertNotNull(actualName, "Expected non-null return value.");
+ assertTrue(ccnxName_Equals(name, actualName), "Expected the same name back");
+
+ ccnxLink_Release(&object);
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&keyId);
+ parcBuffer_Release(&contentObjectHash);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxLink_GetKeyID)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ PARCBuffer *keyId = parcBuffer_Allocate(10);
+ PARCBuffer *contentObjectHash = parcBuffer_Allocate(20);
+
+ CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash);
+
+ PARCBuffer *buffer = ccnxLink_GetKeyID(object);
+ assertNotNull(buffer, "Expected non-null return value.");
+ assertTrue(parcBuffer_Capacity(buffer) == 10, "Expected the same buffer size back");
+
+ ccnxLink_Release(&object);
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&keyId);
+ parcBuffer_Release(&contentObjectHash);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxLink_GetContentObjectHash)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ PARCBuffer *keyId = parcBuffer_Allocate(10);
+ PARCBuffer *contentObjectHash = parcBuffer_Allocate(20);
+
+ CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash);
+
+ PARCBuffer *buffer = ccnxLink_GetContentObjectHash(object);
+ assertNotNull(buffer, "Expected non-null return value.");
+ assertTrue(parcBuffer_Capacity(buffer) == 20, "Expected the same buffer size back");
+
+ ccnxLink_Release(&object);
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&keyId);
+ parcBuffer_Release(&contentObjectHash);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxLink_Equals)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ PARCBuffer *keyId = parcBuffer_Allocate(10);
+ PARCBuffer *contentObjectHash = parcBuffer_Allocate(20);
+ CCNxLink *x = ccnxLink_Create(name, keyId, contentObjectHash);
+ ccnxName_Release(&name);
+ parcBuffer_Release(&keyId);
+ parcBuffer_Release(&contentObjectHash);
+
+ name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ keyId = parcBuffer_Allocate(10);
+ contentObjectHash = parcBuffer_Allocate(20);
+ CCNxLink *y = ccnxLink_Create(name, keyId, contentObjectHash);
+ ccnxName_Release(&name);
+ parcBuffer_Release(&keyId);
+ parcBuffer_Release(&contentObjectHash);
+
+ name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ keyId = parcBuffer_Allocate(10);
+ contentObjectHash = parcBuffer_Allocate(20);
+ CCNxLink *z = ccnxLink_Create(name, keyId, contentObjectHash);
+ ccnxName_Release(&name);
+ parcBuffer_Release(&keyId);
+ parcBuffer_Release(&contentObjectHash);
+
+ name = ccnxName_CreateFromCString("lci:/foo/bar/othername");
+ keyId = parcBuffer_Allocate(10);
+ contentObjectHash = parcBuffer_Allocate(20);
+ CCNxLink *unequal1 = ccnxLink_Create(name, keyId, contentObjectHash);
+ ccnxName_Release(&name);
+ parcBuffer_Release(&keyId);
+ parcBuffer_Release(&contentObjectHash);
+
+ name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ keyId = NULL;
+ contentObjectHash = parcBuffer_Allocate(20);
+ CCNxLink *unequal2 = ccnxLink_Create(name, keyId, contentObjectHash);
+ ccnxName_Release(&name);
+ parcBuffer_Release(&contentObjectHash);
+
+ name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ keyId = parcBuffer_Allocate(10);
+ contentObjectHash = NULL;
+ CCNxLink *unequal3 = ccnxLink_Create(name, keyId, contentObjectHash);
+ ccnxName_Release(&name);
+ parcBuffer_Release(&keyId);
+
+ assertEqualsContract(ccnxLink_Equals, x, y, z, unequal1, unequal2, unequal3);
+
+ ccnxLink_Release(&x);
+ ccnxLink_Release(&y);
+ ccnxLink_Release(&z);
+ ccnxLink_Release(&unequal1);
+ ccnxLink_Release(&unequal2);
+ ccnxLink_Release(&unequal3);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxLink_Create_ToString)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name");
+ PARCBuffer *keyId = parcBuffer_Allocate(10);
+ PARCBuffer *contentObjectHash = parcBuffer_Allocate(20);
+ CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash);
+
+ char *string = ccnxLink_ToString(object);
+ assertNotNull(string, "Expected non-null string.");
+ parcMemory_Deallocate((void **) &string);
+
+ ccnxLink_Release(&object);
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&keyId);
+ parcBuffer_Release(&contentObjectHash);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_Link);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_Manifest.c b/libccnx-common/ccnx/common/test/test_ccnx_Manifest.c
new file mode 100755
index 00000000..583c9a79
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_Manifest.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_Manifest.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <ccnx/common/ccnx_Interest.h>
+
+typedef struct test_data {
+ CCNxManifest *object;
+ CCNxManifest *manifestWithNamelessGroup;
+ CCNxManifest *nameless;
+ PARCLinkedList *interestListFromGroupLocator;
+ PARCLinkedList *interestListFromManifestLocator;
+ PARCLinkedList *interestListFromOverrideLocator;
+ CCNxName *overrideLocator;
+} ManifestTestData;
+
+static ManifestTestData *
+_commonSetup(void)
+{
+ ManifestTestData *data = parcMemory_AllocateAndClear(sizeof(ManifestTestData));
+
+ data->overrideLocator = ccnxName_CreateFromCString("ccnx:/override");
+
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/my/manifest");
+ CCNxManifest *manifest = ccnxManifest_Create(name);
+ CCNxManifest *nameless = ccnxManifest_CreateNameless();
+ CCNxManifest *manifestWithNamelessGroup = ccnxManifest_Create(name);
+
+ data->interestListFromGroupLocator = parcLinkedList_Create();
+ data->interestListFromManifestLocator = parcLinkedList_Create();
+ data->interestListFromOverrideLocator = parcLinkedList_Create();
+ data->object = manifest;
+ data->nameless = nameless;
+ data->manifestWithNamelessGroup = manifestWithNamelessGroup;
+
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ CCNxManifestHashGroup *namelessGroup = ccnxManifestHashGroup_Create();
+
+ CCNxName *locator = ccnxName_CreateFromCString("ccnx:/locator");
+ ccnxManifestHashGroup_SetLocator(group, locator);
+
+ // Create pointers for the pieces of data
+ PARCBuffer *digest1 = parcBuffer_Allocate(32);
+ PARCBuffer *digest2 = parcBuffer_Allocate(32);
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, digest1);
+ ccnxManifestHashGroup_AppendPointer(namelessGroup, CCNxManifestHashGroupPointerType_Data, digest1);
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Manifest, digest2);
+ ccnxManifestHashGroup_AppendPointer(namelessGroup, CCNxManifestHashGroupPointerType_Data, digest2);
+
+ // Create the corresponding interests based on the three locator cases
+ // 1. The locator is inherited from the hash group
+ // 2. The locator is inherited from the manifest
+ // 3. The locator is overridden
+ CCNxInterest *interest1 = ccnxInterest_CreateSimple(locator);
+ ccnxInterest_SetContentObjectHashRestriction(interest1, digest1);
+ parcLinkedList_Append(data->interestListFromGroupLocator, interest1);
+ ccnxInterest_Release(&interest1);
+
+ interest1 = ccnxInterest_CreateSimple(name);
+ ccnxInterest_SetContentObjectHashRestriction(interest1, digest1);
+ parcLinkedList_Append(data->interestListFromManifestLocator, interest1);
+ ccnxInterest_Release(&interest1);
+
+ interest1 = ccnxInterest_CreateSimple(data->overrideLocator);
+ ccnxInterest_SetContentObjectHashRestriction(interest1, digest1);
+ parcLinkedList_Append(data->interestListFromOverrideLocator, interest1);
+ ccnxInterest_Release(&interest1);
+
+ CCNxInterest *interest2 = ccnxInterest_CreateSimple(locator);
+ ccnxInterest_SetContentObjectHashRestriction(interest2, digest2);
+ parcLinkedList_Append(data->interestListFromGroupLocator, interest2);
+ ccnxInterest_Release(&interest2);
+
+ interest2 = ccnxInterest_CreateSimple(name);
+ ccnxInterest_SetContentObjectHashRestriction(interest2, digest2);
+ parcLinkedList_Append(data->interestListFromManifestLocator, interest2);
+ ccnxInterest_Release(&interest2);
+
+ interest2 = ccnxInterest_CreateSimple(data->overrideLocator);
+ ccnxInterest_SetContentObjectHashRestriction(interest2, digest2);
+ parcLinkedList_Append(data->interestListFromOverrideLocator, interest2);
+ ccnxInterest_Release(&interest2);
+
+ ccnxName_Release(&name);
+ ccnxName_Release(&locator);
+ parcBuffer_Release(&digest1);
+ parcBuffer_Release(&digest2);
+
+ ccnxManifest_AddHashGroup(manifest, group);
+ ccnxManifest_AddHashGroup(manifestWithNamelessGroup, namelessGroup);
+ ccnxManifest_AddHashGroup(nameless, namelessGroup);
+
+ ccnxManifestHashGroup_Release(&group);
+ ccnxManifestHashGroup_Release(&namelessGroup);
+
+ return data;
+}
+
+static void
+_commonTeardown(ManifestTestData *data)
+{
+ ccnxManifest_Release(&data->object);
+ ccnxManifest_Release(&data->nameless);
+ ccnxManifest_Release(&data->manifestWithNamelessGroup);
+
+ parcLinkedList_Release(&data->interestListFromGroupLocator);
+ parcLinkedList_Release(&data->interestListFromManifestLocator);
+ parcLinkedList_Release(&data->interestListFromOverrideLocator);
+
+ ccnxName_Release(&data->overrideLocator);
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(ccnx_Manifest)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_Manifest)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_Manifest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_Create);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_AddHashGroup);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_GetHashGroup);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_GetNumberOfHashGroups);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_GetName);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_ToString);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_CreateInterestList_OverrideLocator);
+ // LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_CreateInterestList_ManifestLocator);
+ // LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_CreateInterestList_GroupLocator);
+ // LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_CreateInterestList_NoLocator);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifest_AcquireRelease)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/my/manifest");
+ CCNxManifest *manifest = ccnxManifest_Create(name);
+ ccnxName_Release(&name);
+
+ parcObjectTesting_AssertAcquireReleaseContract(ccnxManifest_Acquire, manifest);
+
+ ccnxManifest_Release(&manifest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifest_Create)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/my/manifest");
+ CCNxManifest *manifest = ccnxManifest_Create(name);
+
+ assertNotNull(manifest, "Expected the Manifest to be created without errors.");
+ const CCNxName *copy = ccnxManifest_GetName(manifest);
+
+ assertTrue(ccnxName_Equals(name, copy), "Expected name to equal %s, got %s", ccnxName_ToString(name), ccnxName_ToString(copy));
+
+ ccnxName_Release(&name);
+ ccnxManifest_Release(&manifest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifest_AddHashGroup)
+{
+ ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxManifest *manifest = data->object;
+
+ size_t numGroups = ccnxManifest_GetNumberOfHashGroups(manifest);
+
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ ccnxManifest_AddHashGroup(manifest, group);
+
+ size_t expected = numGroups + 1;
+ size_t actual = ccnxManifest_GetNumberOfHashGroups(manifest);
+ assertTrue(actual == expected, "Expected %zu, got %zu", expected, actual);
+
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifest_GetHashGroup)
+{
+ ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxManifest *manifest = data->object;
+
+ CCNxManifestHashGroup *group = ccnxManifest_GetHashGroupByIndex(manifest, 0);
+ CCNxName *expected = ccnxName_CreateFromCString("ccnx:/locator");
+ const CCNxName *actual = ccnxManifestHashGroup_GetLocator(group);
+ assertTrue(ccnxName_Equals(expected, actual), "Expected %s, got %s", ccnxName_ToString(expected), ccnxName_ToString(actual));
+
+ ccnxName_Release(&expected);
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifest_GetNumberOfHashGroups)
+{
+ ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxManifest *manifest = data->object;
+
+ size_t before = ccnxManifest_GetNumberOfHashGroups(manifest);
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ ccnxManifest_AddHashGroup(manifest, group);
+
+ size_t actual = ccnxManifest_GetNumberOfHashGroups(manifest);
+ size_t expected = before + 1;
+
+ assertTrue(expected == actual, "Expected %zu, got %zu", expected, actual);
+
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifest_CreateInterestList_NoLocator)
+{
+ ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxManifest *nameless = data->nameless;
+
+ PARCLinkedList *interestList = ccnxManifest_CreateInterestList(nameless, NULL);
+ assertTrue(parcLinkedList_Size(interestList) == 0, "Expected the interest list to be empty since there was no valid locator");
+ parcLinkedList_Release(&interestList);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifest_CreateInterestList_GroupLocator)
+{
+ ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxManifest *manifest = data->object;
+
+ PARCLinkedList *interestList = ccnxManifest_CreateInterestList(manifest, NULL);
+ assertTrue(parcLinkedList_Equals(interestList, data->interestListFromGroupLocator), "Expected the interest lists to be equal");
+ parcLinkedList_Release(&interestList);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifest_CreateInterestList_ManifestLocator)
+{
+ ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxManifest *manifestWithNamelessGroup = data->manifestWithNamelessGroup;
+
+ PARCLinkedList *interestList = ccnxManifest_CreateInterestList(manifestWithNamelessGroup, NULL);
+ assertTrue(parcLinkedList_Equals(interestList, data->interestListFromManifestLocator), "Expected the interest lists to be equal");
+ parcLinkedList_Release(&interestList);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifest_CreateInterestList_OverrideLocator)
+{
+ ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxManifest *nameless = data->nameless;
+ CCNxName *overrideLocator = data->overrideLocator;
+
+ PARCLinkedList *interestList = ccnxManifest_CreateInterestList(nameless, overrideLocator);
+ assertTrue(parcLinkedList_Equals(interestList, data->interestListFromOverrideLocator), "Expected the interest lists to be equal");
+ parcLinkedList_Release(&interestList);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifest_GetName)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/my/manifest");
+ CCNxManifest *manifest = ccnxManifest_Create(name);
+
+ assertNotNull(manifest, "Expected the Manifest to be created without errors.");
+ const CCNxName *copy = ccnxManifest_GetName(manifest);
+
+ assertTrue(ccnxName_Equals(name, copy), "Expected name to equal %s, got %s", ccnxName_ToString(name), ccnxName_ToString(copy));
+
+ ccnxName_Release(&name);
+ ccnxManifest_Release(&manifest);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifest_Equals)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/my/manifest");
+ CCNxManifest *x = ccnxManifest_Create(name);
+ CCNxManifest *y = ccnxManifest_Create(name);
+ CCNxManifest *z = ccnxManifest_Create(name);
+
+ CCNxName *name1 = ccnxName_CreateFromCString("ccnx:/not/my/manifest");
+ CCNxManifest *u1 = ccnxManifest_Create(name1);
+
+ parcObjectTesting_AssertEqualsFunction(ccnxManifest_Equals, x, y, z, u1, NULL);
+
+ ccnxName_Release(&name);
+ ccnxName_Release(&name1);
+ ccnxManifest_Release(&x);
+ ccnxManifest_Release(&y);
+ ccnxManifest_Release(&z);
+ ccnxManifest_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifest_ToString)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/my/manifest");
+ CCNxManifest *manifest = ccnxManifest_Create(name);
+
+ assertNotNull(manifest, "Expected the Manifest to be created without errors.");
+ const CCNxName *copy = ccnxManifest_GetName(manifest);
+
+ assertTrue(ccnxName_Equals(name, copy), "Expected name to equal %s, got %s", ccnxName_ToString(name), ccnxName_ToString(copy));
+
+ ccnxName_Release(&name);
+ ccnxManifest_Release(&manifest);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_Manifest);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_ManifestHashGroup.c b/libccnx-common/ccnx/common/test/test_ccnx_ManifestHashGroup.c
new file mode 100644
index 00000000..c09fa63d
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_ManifestHashGroup.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_ManifestHashGroup.c"
+
+#include <inttypes.h>
+#include <ccnx/common/ccnx_Manifest.h>
+
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h>
+#include <ccnx/common/codec/ccnxCodec_TlvPacket.h>
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_ArrayList.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(ccnx_ManifestHashGroup)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_ManifestHashGroup)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_ManifestHashGroup)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_Create);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_CreateFromJson);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_AppendGetPointer);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_PrependGetPointer);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_ToJson);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_IsFull);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_CreateInterestList_GroupLocator);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_CreateInterestList_OverrideLocator);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_CreateInterestList_NoLocator);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_Iterator);
+
+ // Metadata
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_BlockSize);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_DataSize);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_EntrySize);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_TreeHeight);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_Locator);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_OverallDataDigest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_HasMetadata);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_AcquireRelease)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ parcObjectTesting_AssertAcquireReleaseContract(ccnxManifestHashGroup_Acquire, group);
+
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_Create)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_CreateFromJson)
+{
+ char *jsonString = "{ \"HashGroup\" : [ { \"type\" : 0, \"digest\" : \"FFFF\" } ] }";
+ PARCJSON *json = parcJSON_ParseString(jsonString);
+
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_CreateFromJson(json);
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ size_t actual = ccnxManifestHashGroup_GetNumberOfPointers(group);
+ size_t expected = 1;
+
+ assertTrue(actual == expected, "Expected %zu pointers, got %zu", expected, actual);
+
+ parcJSON_Release(&json);
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_AppendGetPointer)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ PARCBuffer *buffer1 = parcBuffer_Allocate(32);
+ PARCBuffer *buffer2 = parcBuffer_Allocate(32);
+
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer1);
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Manifest, buffer2);
+
+ size_t expected = 2;
+ size_t actual = ccnxManifestHashGroup_GetNumberOfPointers(group);
+
+ assertTrue(expected == actual, "Expected %zu, got %zu", expected, actual);
+ assertTrue(ccnxManifestHashGroupPointer_GetType(ccnxManifestHashGroup_GetPointerAtIndex(group, 0)) == CCNxManifestHashGroupPointerType_Data, "Expected data in the first slot");
+ assertTrue(ccnxManifestHashGroupPointer_GetType(ccnxManifestHashGroup_GetPointerAtIndex(group, 1)) == CCNxManifestHashGroupPointerType_Manifest, "Expected data in the first slot");
+
+ parcBuffer_Release(&buffer1);
+ parcBuffer_Release(&buffer2);
+
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_PrependGetPointer)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ PARCBuffer *buffer1 = parcBuffer_Allocate(32);
+ PARCBuffer *buffer2 = parcBuffer_Allocate(32);
+
+ ccnxManifestHashGroup_PrependPointer(group, CCNxManifestHashGroupPointerType_Data, buffer1);
+ ccnxManifestHashGroup_PrependPointer(group, CCNxManifestHashGroupPointerType_Manifest, buffer2);
+
+ size_t expected = 2;
+ size_t actual = ccnxManifestHashGroup_GetNumberOfPointers(group);
+
+ assertTrue(expected == actual, "Expected %zu, got %zu", expected, actual);
+ assertTrue(ccnxManifestHashGroupPointer_GetType(ccnxManifestHashGroup_GetPointerAtIndex(group, 1)) == CCNxManifestHashGroupPointerType_Data, "Expected data in the first slot");
+ assertTrue(ccnxManifestHashGroupPointer_GetType(ccnxManifestHashGroup_GetPointerAtIndex(group, 0)) == CCNxManifestHashGroupPointerType_Manifest, "Expected data in the first slot");
+
+ parcBuffer_Release(&buffer1);
+ parcBuffer_Release(&buffer2);
+
+ ccnxManifestHashGroup_Release(&group);
+}
+
+static CCNxManifestHashGroup *
+_createHashGroup(CCNxName *locator, size_t n, size_t blockSize, size_t dataSize, size_t entrySize, size_t treeHeight)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+
+ if (locator != NULL) {
+ ccnxManifestHashGroup_SetLocator(group, locator);
+ }
+
+ for (size_t i = 0; i < n; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(32);
+ ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ if (blockSize != 0) {
+ ccnxManifestHashGroup_SetBlockSize(group, blockSize);
+ }
+
+ if (dataSize != 0) {
+ ccnxManifestHashGroup_SetDataSize(group, dataSize);
+ }
+
+ if (entrySize != 0) {
+ ccnxManifestHashGroup_SetEntrySize(group, entrySize);
+ }
+
+ if (treeHeight != 0) {
+ ccnxManifestHashGroup_SetTreeHeight(group, treeHeight);
+ }
+
+ return group;
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_Equals)
+{
+ CCNxName *locator = ccnxName_CreateFromCString("ccnx:/my/manifest");
+
+ CCNxManifestHashGroup *x = _createHashGroup(locator, 10, 0, 0, 0, 0);
+ CCNxManifestHashGroup *y = _createHashGroup(locator, 10, 0, 0, 0, 0);
+ CCNxManifestHashGroup *z = _createHashGroup(locator, 10, 0, 0, 0, 0);
+
+ CCNxManifestHashGroup *u1 = _createHashGroup(locator, 5, 0, 0, 0, 0);
+ CCNxManifestHashGroup *u2 = _createHashGroup(NULL, 10, 0, 0, 0, 0);
+ CCNxManifestHashGroup *u3 = _createHashGroup(locator, 10, 1, 0, 0, 0);
+ CCNxManifestHashGroup *u4 = _createHashGroup(locator, 10, 0, 1, 0, 0);
+ CCNxManifestHashGroup *u5 = _createHashGroup(locator, 10, 0, 0, 1, 0);
+ CCNxManifestHashGroup *u6 = _createHashGroup(locator, 10, 0, 0, 0, 1);
+
+ parcObjectTesting_AssertEqualsFunction(ccnxManifestHashGroup_Equals, x, y, z, u1, u2, u3, u4, u5, u6, NULL);
+
+ ccnxManifestHashGroup_Release(&x);
+ ccnxManifestHashGroup_Release(&y);
+ ccnxManifestHashGroup_Release(&z);
+
+ ccnxManifestHashGroup_Release(&u1);
+ ccnxManifestHashGroup_Release(&u2);
+ ccnxManifestHashGroup_Release(&u3);
+ ccnxManifestHashGroup_Release(&u4);
+ ccnxManifestHashGroup_Release(&u5);
+ ccnxManifestHashGroup_Release(&u6);
+
+ ccnxName_Release(&locator);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_ToString)
+{
+ char *jsonString = "{ \"HashGroup\" : [ { \"type\" : 0, \"digest\" : \"617364617364617364\" } ] }";
+ PARCJSON *json = parcJSON_ParseString(jsonString);
+
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_CreateFromJson(json);
+
+ char *stringForm = ccnxManifestHashGroup_ToString(group);
+ assertTrue(strcmp(jsonString, stringForm) == 0, "Expected %s and actual %s should be equal.", jsonString, stringForm);
+
+ parcMemory_Deallocate(&stringForm);
+ parcJSON_Release(&json);
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_ToJson)
+{
+ char *jsonString = "{ \"HashGroup\" : [ { \"type\" : 0, \"digest\" : \"617364617364617364\" } ] }";
+ PARCJSON *json = parcJSON_ParseString(jsonString);
+
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_CreateFromJson(json);
+ PARCJSON *expected = ccnxManifestHashGroup_ToJson(group);
+
+ assertTrue(parcJSON_Equals(json, expected), "Expected the input and output JSON to be identical");
+
+ parcJSON_Release(&expected);
+ parcJSON_Release(&json);
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_IsFull)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ for (size_t i = 0; i < MAX_NUMBER_OF_POINTERS; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(32);
+ assertTrue(ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer), "Expected the insertion to succeed");
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCBuffer *buffer = parcBuffer_Allocate(32);
+ assertFalse(ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer), "Expected the insertion to fail since the HashGroup is full.");
+ parcBuffer_Release(&buffer);
+
+ bool isFull = ccnxManifestHashGroup_IsFull(group);
+ assertTrue(isFull, "Expected the group to be full after %ul pointers", MAX_NUMBER_OF_POINTERS);
+
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_CreateInterestList_OverrideLocator)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ PARCLinkedList *interestList = parcLinkedList_Create();
+ CCNxName *locator = ccnxName_CreateFromCString("ccnx:/locator");
+ for (size_t i = 0; i < MAX_NUMBER_OF_POINTERS; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(32);
+ assertTrue(ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer), "Expected the insertion to succeed");
+
+ CCNxInterest *interest = ccnxInterest_CreateSimple(locator);
+ ccnxInterest_SetContentObjectHashRestriction(interest, buffer);
+ parcLinkedList_Append(interestList, interest);
+
+ ccnxInterest_Release(&interest);
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCLinkedList *extractedList = ccnxManifestHashGroup_CreateInterestList(group, locator);
+ assertTrue(parcLinkedList_Equals(interestList, extractedList), "Expected the interest lists to be equal");
+
+ parcLinkedList_Release(&interestList);
+ parcLinkedList_Release(&extractedList);
+ ccnxName_Release(&locator);
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_CreateInterestList_GroupLocator)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ CCNxName *locator = ccnxName_CreateFromCString("ccnx:/group/locator");
+ ccnxManifestHashGroup_SetLocator(group, locator);
+
+ PARCLinkedList *interestList = parcLinkedList_Create();
+ for (size_t i = 0; i < MAX_NUMBER_OF_POINTERS; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(32);
+ assertTrue(ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer), "Expected the insertion to succeed");
+
+ CCNxInterest *interest = ccnxInterest_CreateSimple(locator);
+ ccnxInterest_SetContentObjectHashRestriction(interest, buffer);
+ parcLinkedList_Append(interestList, interest);
+
+ ccnxInterest_Release(&interest);
+ parcBuffer_Release(&buffer);
+ }
+
+ CCNxName *differentLocator = ccnxName_CreateFromCString("ccnx:/different/locator");
+ PARCLinkedList *extractedList = ccnxManifestHashGroup_CreateInterestList(group, differentLocator);
+ ccnxName_Release(&differentLocator);
+ assertTrue(parcLinkedList_Equals(interestList, extractedList), "Expected the interest lists to be equal");
+
+ parcLinkedList_Release(&interestList);
+ parcLinkedList_Release(&extractedList);
+ ccnxName_Release(&locator);
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_CreateInterestList_NoLocator)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ for (size_t i = 0; i < MAX_NUMBER_OF_POINTERS; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(32);
+ assertTrue(ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer), "Expected the insertion to succeed");
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCLinkedList *extractedList = ccnxManifestHashGroup_CreateInterestList(group, NULL);
+ assertTrue(parcLinkedList_Size(extractedList) == 0, "Expected the interest list to be empty since there was no valid locator");
+
+ parcLinkedList_Release(&extractedList);
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_BlockSize)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ size_t blockSize = 10;
+ ccnxManifestHashGroup_SetBlockSize(group, blockSize);
+ size_t actual = ccnxManifestHashGroup_GetBlockSize(group);
+
+ assertTrue(blockSize == actual, "Expected %zu, got %zu", blockSize, actual);
+
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_DataSize)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ size_t dataSize = 10;
+ ccnxManifestHashGroup_SetDataSize(group, dataSize);
+ size_t actual = ccnxManifestHashGroup_GetDataSize(group);
+
+ assertTrue(dataSize == actual, "Expected %zu, got %zu", dataSize, actual);
+
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_EntrySize)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ size_t entrySize = 10;
+ ccnxManifestHashGroup_SetEntrySize(group, entrySize);
+ size_t actual = ccnxManifestHashGroup_GetEntrySize(group);
+
+ assertTrue(entrySize == actual, "Expected %zu, got %zu", entrySize, actual);
+
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_TreeHeight)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ size_t treeHeight = 10;
+ ccnxManifestHashGroup_SetTreeHeight(group, treeHeight);
+ size_t actual = ccnxManifestHashGroup_GetTreeHeight(group);
+
+ assertTrue(treeHeight == actual, "Expected %zu, got %zu", treeHeight, actual);
+
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_OverallDataDigest)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ PARCBuffer *digest = parcBuffer_Allocate(10);
+ ccnxManifestHashGroup_SetOverallDataDigest(group, digest);
+ const PARCBuffer *actual = ccnxManifestHashGroup_GetOverallDataDigest(group);
+
+ assertTrue(parcBuffer_Equals(digest, actual) == true, "Expected %s, got %s", parcBuffer_ToHexString(digest), parcBuffer_ToHexString(actual));
+
+ parcBuffer_Release(&digest);
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_Locator)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ CCNxName *expected = ccnxName_CreateFromCString("ccnx:/flic/manifest");
+ ccnxManifestHashGroup_SetLocator(group, expected);
+ const CCNxName *actual = ccnxManifestHashGroup_GetLocator(group);
+
+ assertTrue(ccnxName_Equals(expected, actual) == true, "Expected %s, got %s", ccnxName_ToString(expected), ccnxName_ToString(actual));
+
+ ccnxName_Release(&expected);
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_HasMetadata)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ assertFalse(ccnxManifestHashGroup_HasMetadata(group), "Expected an empty HashGroup to have no metadata");
+
+ CCNxName *expected = ccnxName_CreateFromCString("ccnx:/flic/manifest");
+ ccnxManifestHashGroup_SetLocator(group, expected);
+
+ assertTrue(ccnxManifestHashGroup_HasMetadata(group), "Expected a HashGroup with a locator to have metadata");
+
+ ccnxName_Release(&expected);
+ ccnxManifestHashGroup_Release(&group);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_Iterator)
+{
+ CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create();
+ assertNotNull(group, "Expected non-null CCNxManifestHashGroup");
+
+ for (size_t i = 0; i < MAX_NUMBER_OF_POINTERS; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_Flip(parcBuffer_PutUint32(buffer, i));
+ assertTrue(ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer), "Expected the insertion to succeed");
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCIterator *itr = ccnxManifestHashGroup_Iterator(group);
+
+ size_t i = 0;
+ while (parcIterator_HasNext(itr)) {
+ CCNxManifestHashGroupPointer *ptr = (CCNxManifestHashGroupPointer *) parcIterator_Next(itr);
+ const PARCBuffer *digest = ccnxManifestHashGroupPointer_GetDigest(ptr);
+ size_t index = parcBuffer_GetUint32((PARCBuffer *) digest);
+ assertTrue(index == i, "Expected the right digest pointer to be extracted, got %zu, expected %zu", index, i);
+ i++;
+ }
+
+ parcIterator_Release(&itr);
+
+ bool isFull = ccnxManifestHashGroup_IsFull(group);
+ assertTrue(isFull, "Expected the group to be full after %ul pointers", MAX_NUMBER_OF_POINTERS);
+
+ ccnxManifestHashGroup_Release(&group);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ManifestHashGroup);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_Name.c b/libccnx-common/ccnx/common/test/test_ccnx_Name.c
new file mode 100644
index 00000000..2adec939
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_Name.c
@@ -0,0 +1,735 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include "../ccnx_Name.c"
+
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+#include <limits.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(ccnx_Name)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Specialization);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(ccnx_Name)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_Name)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateFromCString);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateFromCString_Root);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateFromCString_BadScheme);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateFromCString_NoScheme);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateFromCString_ZeroComponents);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateFromBuffer);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_IsValid_True);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_IsValid_False);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_LeftMostHashCode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_HashCode_LeftMostHashCode);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_ToString_Root);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_ToString_NoPath);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_ToString_LCI);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_Copy_Zero);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_Copy_NonZero);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateAndDestroy);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_Trim);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_Trim_MAXINT);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_StartsWith_True);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_StartsWith_FalseShorterPrefix);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_StartsWith_FalseLongerPrefix);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxName_ComposeNAME);
+
+ LONGBOW_RUN_TEST_CASE(Global, ParseTest1);
+ LONGBOW_RUN_TEST_CASE(Global, ParseTest2);
+
+ LONGBOW_RUN_TEST_CASE(Global, MemoryProblem);
+}
+
+static size_t _longBowGlobal_Global_outstanding;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ size_t allocationsLeaked = parcMemory_Outstanding() - _longBowGlobal_Global_outstanding;
+
+ if (allocationsLeaked > 0) {
+ printf("%s leaks memory by %zd allocations\n", longBowTestCase_GetName(testCase), allocationsLeaked);
+ parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ result = LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return result;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_ComposeNAME)
+{
+ char *string = "lci:/a/b/c";
+
+ CCNxName *basename = ccnxName_CreateFromCString("lci:/a/b");
+ CCNxName *expected = ccnxName_CreateFromCString(string);
+
+ CCNxName *actual = ccnxName_ComposeNAME(basename, "c");
+ assertTrue(ccnxName_Equals(expected, actual), "Failed.");
+
+ ccnxName_Release(&basename);
+ ccnxName_Release(&expected);
+ ccnxName_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_IsValid_True)
+{
+ char *string = "lci:/a/b/c";
+ CCNxName *name = ccnxName_CreateFromCString(string);
+ assertTrue(ccnxName_IsValid(name), "Expected %s to be a valid CCNxName.", string);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_IsValid_False)
+{
+ assertFalse(ccnxName_IsValid(NULL), "Expected NULL to be an invalid CCNxName.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_Equals)
+{
+ CCNxName *x = ccnxName_CreateFromCString("lci:/a/b/c");
+ CCNxName *y = ccnxName_CreateFromCString("lci:/a/b/c");
+ CCNxName *z = ccnxName_CreateFromCString("lci:/a/b/c");
+ CCNxName *u1 = ccnxName_CreateFromCString("lci:/a/b");
+ CCNxName *u2 = ccnxName_CreateFromCString("lci:/a/b/d");
+
+ assertEqualsContract(ccnxName_Equals, x, y, z, u1, u2);
+
+ ccnxName_Release(&x);
+ ccnxName_Release(&y);
+ ccnxName_Release(&z);
+ ccnxName_Release(&u1);
+ ccnxName_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_ToString_Root)
+{
+ const char *expected = "ccnx:/";
+
+ CCNxName *name = ccnxName_CreateFromCString(expected);
+
+ char *actual = ccnxName_ToString(name);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ ccnxName_Release(&name);
+
+ name = ccnxName_CreateFromCString("ccnx:");
+ actual = ccnxName_ToString(name);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_ToString_NoPath)
+{
+ const char *expected = "ccnx:/";
+
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:");
+
+ char *actual = ccnxName_ToString(name);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_Trim)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/a/b/c");
+
+ ccnxName_Trim(name, 1);
+
+ const char *expected = "ccnx:/a/b";
+ char *actual = ccnxName_ToString(name);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_Trim_MAXINT)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/a/b/c");
+
+ ccnxName_Trim(name, INT_MAX);
+
+ const char *expected = "ccnx:/";
+ char *actual = ccnxName_ToString(name);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_Copy_Zero)
+{
+ const char *uri = "ccnx:/"; // A Name with 1 zero-length segment
+
+ CCNxName *name = ccnxName_CreateFromCString(uri);
+
+ CCNxName *copy = ccnxName_Copy(name);
+ assertNotNull(copy, "Expect non-null result.");
+
+ char *expected = ccnxName_ToString(name);
+ char *actual = ccnxName_ToString(copy);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ ccnxName_Release(&name);
+ ccnxName_Release(&copy);
+ parcMemory_Deallocate((void **) &expected);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_Copy_NonZero)
+{
+ const char *uri = "ccnx:/a/b/c/d/e";
+
+ CCNxName *name = ccnxName_CreateFromCString(uri);
+
+ CCNxName *copy = ccnxName_Copy(name);
+ assertNotNull(copy, "Expect non-null result.");
+
+ char *expected = ccnxName_ToString(name);
+ char *actual = ccnxName_ToString(copy);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ ccnxName_Release(&name);
+ ccnxName_Release(&copy);
+ parcMemory_Deallocate((void **) &expected);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_HashCode)
+{
+ const char *uriA = "lci:/a/b/c/d/e/";
+ const char *uriB = "lci:/a/b/c/d/e/";
+
+ CCNxName *nameA = ccnxName_CreateFromCString(uriA);
+ CCNxName *nameB = ccnxName_CreateFromCString(uriB);
+
+ PARCHashCode codeA = ccnxName_HashCode(nameA);
+ PARCHashCode codeB = ccnxName_HashCode(nameB);
+
+ // We know the hashcode of uriA is not zero
+ assertTrue(codeA != 0, "Expected a non-zero hash code");
+
+ assertTrue(codeA == codeB, "Expected %" PRIPARCHashCode " == %" PRIPARCHashCode, codeA, codeB);
+
+ ccnxName_Release(&nameA);
+ ccnxName_Release(&nameB);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_HashCode_LeftMostHashCode)
+{
+ const char *uriA = "lci:/a/b/c/d/e/";
+ const char *uriB = "lci:/a/b/c/d/e/";
+
+ CCNxName *nameA = ccnxName_CreateFromCString(uriA);
+ CCNxName *nameB = ccnxName_CreateFromCString(uriB);
+
+ PARCHashCode codeA = ccnxName_HashCode(nameA);
+ PARCHashCode codeB = ccnxName_HashCode(nameB);
+ PARCHashCode leftMostCodeA = ccnxName_LeftMostHashCode(nameA, INT_MAX);
+ PARCHashCode leftMostCodeB = ccnxName_LeftMostHashCode(nameB, INT_MAX);
+
+ // We know the hashcode of uriA is not zero
+ assertTrue(codeA != 0, "Expected a non-zero hash code");
+
+ assertTrue(codeA == codeB, "Expected %" PRIPARCHashCode " == %" PRIPARCHashCode, codeA, codeB);
+ assertTrue(codeA == leftMostCodeA, "Expected %" PRIPARCHashCode " == %" PRIPARCHashCode, codeA, leftMostCodeA);
+ assertTrue(codeA == leftMostCodeB, "Expected %" PRIPARCHashCode " == %" PRIPARCHashCode, codeA, leftMostCodeB);
+
+ ccnxName_Release(&nameA);
+ ccnxName_Release(&nameB);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_LeftMostHashCode)
+{
+ const char *uriA = "lci:/a/b/c/d/e/";
+ const char *uriB = "lci:/a/b/c/d/e/";
+
+ CCNxName *nameA = ccnxName_CreateFromCString(uriA);
+ CCNxName *nameB = ccnxName_CreateFromCString(uriB);
+
+ PARCHashCode codeA = ccnxName_LeftMostHashCode(nameA, 2);
+ PARCHashCode codeB = ccnxName_LeftMostHashCode(nameB, 2);
+
+ assertTrue(codeA == codeB, "Expected %" PRIPARCHashCode " == %" PRIPARCHashCode, codeA, codeB);
+
+ ccnxName_Release(&nameA);
+ ccnxName_Release(&nameB);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_CreateAndDestroy)
+{
+ CCNxName *name = ccnxName_Create();
+ assertNotNull(name, "Expected non-null");
+ ccnxName_Release(&name);
+ assertNull(name, "Expected null");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_CreateFromCString)
+{
+ const char *uri = "lci:/CCN-Python-Test";
+
+ CCNxName *name = ccnxName_CreateFromCString(uri);
+ ccnxName_Display(name, 0);
+ assertNotNull(name, "Expected non-null");
+
+ size_t expected = 1;
+ size_t actual = ccnxName_GetSegmentCount(name);
+
+ assertTrue(expected == actual, "Expected %zd segments, actual %zd", expected, actual);
+
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_CreateFromCString_BadScheme)
+{
+ const char *uri = "abcd:/CCN-Python-Test/Echo";
+
+ CCNxName *name = ccnxName_CreateFromCString(uri);
+ assertNull(name, "Expected null");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_CreateFromCString_NoScheme)
+{
+ const char *uri = "/paravion";
+
+ CCNxName *name = ccnxName_CreateFromCString(uri);
+ assertNull(name, "Expected null");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_CreateFromCString_ZeroComponents)
+{
+ const char *uri = "lci:";
+
+ CCNxName *name = ccnxName_CreateFromCString(uri);
+ assertNotNull(name, "Expected non-null result from ccnxName_CreateFromCString");
+
+ size_t expected = 0;
+ size_t actual = ccnxName_GetSegmentCount(name);
+
+ assertTrue(expected == actual, "Expected %zd segments, actual %zd", expected, actual);
+
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_CreateFromCString_Root)
+{
+ const char *uri = "lci:/";
+
+ CCNxName *name = ccnxName_CreateFromCString(uri);
+ assertNotNull(name, "Expected non-null");
+
+ size_t expected = 1;
+ size_t actual = ccnxName_GetSegmentCount(name);
+
+ assertTrue(expected == actual, "Expected %zd segments, actual %zd", expected, actual);
+
+ CCNxNameSegment *segment = ccnxName_GetSegment(name, 0);
+
+ size_t segmentLength = ccnxNameSegment_Length(segment);
+ assertTrue(segmentLength == 0, "Expected a zero length segment, actual %zd", segmentLength);
+
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_CreateFromBuffer)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("lci:/CCN-Python-Test");
+ CCNxName *name = ccnxName_CreateFromBuffer(buffer);
+ assertNotNull(name, "Expected non-null");
+
+ size_t expected = 1;
+ size_t actual = ccnxName_GetSegmentCount(name);
+
+ assertTrue(expected == actual, "Expected %zd segments, actual %zd", expected, actual);
+
+ ccnxName_Release(&name);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_ToString_LCI)
+{
+ const char *lci = "lci:/a/b";
+ const char *expectedURI = "ccnx:/a/b";
+
+ CCNxName *name = ccnxName_CreateFromCString(lci);
+
+ size_t expected = 2;
+ size_t actual = ccnxName_GetSegmentCount(name);
+
+ assertTrue(expected == actual,
+ "Expected %zd segments, actual %zd", expected, actual);
+
+ char *string = ccnxName_ToString(name);
+ assertTrue(strcmp(expectedURI, string) == 0,
+ "Expected '%s' actual '%s'", expectedURI, string);
+ parcMemory_Deallocate((void **) &string);
+
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_ToString)
+{
+ const char *uri = "ccnx:/a/b";
+
+ CCNxName *name = ccnxName_CreateFromCString(uri);
+
+ size_t expected = 2;
+ size_t actual = ccnxName_GetSegmentCount(name);
+
+ assertTrue(expected == actual,
+ "Expected %zd segments, actual %zd", expected, actual);
+
+ char *string = ccnxName_ToString(name);
+ assertTrue(strcmp(uri, string) == 0,
+ "Expected '%s' actual '%s'", uri, string);
+ parcMemory_Deallocate((void **) &string);
+
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_Compare)
+{
+ CCNxName *value = ccnxName_CreateFromCString("lci:/a/b/c");
+ CCNxName *equal1 = ccnxName_CreateFromCString("lci:/a/b/c");
+
+ CCNxName **equivalents = (CCNxName *[]) {
+ equal1,
+ NULL
+ };
+
+ CCNxName *lesser1 = ccnxName_CreateFromCString("lci:/a/b");
+ CCNxName *lesser2 = ccnxName_CreateFromCString("lci:/a/b/b");
+ CCNxName **lesser = (CCNxName *[]) {
+ lesser1,
+ lesser2,
+ NULL
+ };
+
+ CCNxName *greater1 = ccnxName_CreateFromCString("lci:/a/b/d");
+ CCNxName *greater2 = ccnxName_CreateFromCString("lci:/a/b/c/d");
+ CCNxName **greater = (CCNxName *[]) {
+ greater1,
+ greater2,
+ NULL
+ };
+
+ assertCompareToContract(ccnxName_Compare, value, equivalents, lesser, greater);
+
+ for (int i = 0; lesser[i] != NULL; i++) {
+ ccnxName_Release(&lesser[i]);
+ }
+ for (int i = 0; greater[i] != NULL; i++) {
+ ccnxName_Release(&greater[i]);
+ }
+ for (int i = 0; equivalents[i] != NULL; i++) {
+ ccnxName_Release(&equivalents[i]);
+ }
+ ccnxName_Release(&value);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_StartsWith_True)
+{
+ const char *uriA = "lci:/a/b/c/d/e/";
+ const char *uriB = "lci:/a/b/c/d/e/";
+
+ CCNxName *nameA = ccnxName_CreateFromCString(uriA);
+ CCNxName *nameB = ccnxName_CreateFromCString(uriB);
+
+ bool actual = ccnxName_StartsWith(nameA, nameA);
+
+ assertTrue(actual, "Expected true");
+
+ ccnxName_Release(&nameA);
+ ccnxName_Release(&nameB);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_StartsWith_FalseShorterPrefix)
+{
+ const char *uriA = "lci:/a/b/c/d/e";
+ const char *prefix = "lci:/a/b/d";
+
+ CCNxName *nameA = ccnxName_CreateFromCString(uriA);
+ CCNxName *nameB = ccnxName_CreateFromCString(prefix);
+
+ bool actual = ccnxName_StartsWith(nameA, nameB);
+
+ assertFalse(actual, "Expected false");
+
+ ccnxName_Release(&nameA);
+ ccnxName_Release(&nameB);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxName_StartsWith_FalseLongerPrefix)
+{
+ const char *uriA = "lci:/a/b/c/d/e";
+ const char *prefix = "lci:/a/b/c/d/e/f";
+
+ CCNxName *nameA = ccnxName_CreateFromCString(uriA);
+ CCNxName *nameB = ccnxName_CreateFromCString(prefix);
+
+ bool actual = ccnxName_StartsWith(nameA, nameB);
+
+ assertFalse(actual, "Expected false");
+
+ ccnxName_Release(&nameA);
+ ccnxName_Release(&nameB);
+}
+
+static CCNxNameSegment *
+createSegment(PARCBuffer *buffer, size_t start, size_t end)
+{
+ parcBuffer_SetPosition(buffer, start);
+ PARCBuffer *slice = parcBuffer_Slice(buffer);
+ parcBuffer_SetLimit(slice, end);
+
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, slice);
+ parcBuffer_Release(&slice);
+
+ return segment;
+}
+
+LONGBOW_TEST_CASE(Global, MemoryProblem)
+{
+ char memory[] = "abcdefghijklmnopqrstuvwxyz";
+ PARCBuffer *buffer = parcBuffer_Wrap(memory, sizeof(memory), 0, sizeof(memory));
+
+ CCNxName *name = ccnxName_Create();
+
+ CCNxNameSegment *segment1 = createSegment(buffer, 2, 4); // "cd"
+ ccnxName_Append(name, segment1);
+
+ CCNxNameSegment *segment2 = createSegment(buffer, 10, 14); // "klmn"
+ ccnxName_Append(name, segment2);
+
+ CCNxName *name2 = ccnxName_Acquire(name);
+
+ parcBuffer_Release(&buffer);
+ ccnxName_Release(&name2);
+
+ ccnxName_Release(&name);
+ ccnxNameSegment_Release(&segment1);
+ ccnxNameSegment_Release(&segment2);
+}
+
+LONGBOW_TEST_CASE(Global, ParseTest1)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/" CCNxNameLabel_Name "=foot/3=toe/4=nail");
+ assertNotNull(name, "Expected non-null value from ccnxName_CreateFromCString");
+
+ ccnxName_Display(name, 0);
+
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ParseTest2)
+{
+ CCNxName *a = ccnxName_CreateFromCString("lci:/a/b/c");
+ CCNxName *b = ccnxName_CreateFromCString("lci:/Name=a/Name=b/Name=c");
+ assertTrue(ccnxName_Equals(a, b), "Expected to be equal");
+ ccnxName_Release(&a);
+ ccnxName_Release(&b);
+
+ char *expected = "ccnx:/test/Name=MiISAg%3D%3D";
+ CCNxName *name = ccnxName_CreateFromCString(expected);
+ assertNotNull(name, "Expected non-null value from ccnxName_CreateFromCString");
+ char *actual = ccnxName_ToString(name);
+ printf("%s\n", actual);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate(&actual);
+
+ ccnxName_Display(name, 0);
+
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, ccnxName_Prefix);
+ LONGBOW_RUN_TEST_CASE(Specialization, ccnxName_Prefix_Excess);
+ LONGBOW_RUN_TEST_CASE(Specialization, ccnxName_Prefix_0);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialization, ccnxName_Prefix)
+{
+ CCNxName *a = ccnxName_CreateFromCString("ccnx:/a/b/c");
+ CCNxName *expected = ccnxName_CreateFromCString("ccnx:/a");
+
+ CCNxName *actual = ccnxName_CreatePrefix(a, 1);
+
+ assertTrue(ccnxName_Equals(expected, actual), "Mismatched results.");
+
+ ccnxName_Release(&a);
+ ccnxName_Release(&expected);
+ ccnxName_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Specialization, ccnxName_Prefix_Excess)
+{
+ CCNxName *a = ccnxName_CreateFromCString("ccnx:/a/b/c");
+ CCNxName *expected = ccnxName_CreateFromCString("ccnx:/a/b/c");
+
+ CCNxName *actual = ccnxName_CreatePrefix(a, 100);
+
+ assertTrue(ccnxName_Equals(expected, actual), "Mismatched results.");
+
+ ccnxName_Release(&a);
+ ccnxName_Release(&expected);
+ ccnxName_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Specialization, ccnxName_Prefix_0)
+{
+ CCNxName *a = ccnxName_CreateFromCString("ccnx:/a/b/c");
+ CCNxName *expected = ccnxName_CreateFromCString("ccnx:");
+
+ CCNxName *actual = ccnxName_CreatePrefix(a, 0);
+
+ assertTrue(ccnxName_Equals(expected, actual), "Mismatched results.");
+
+ ccnxName_Release(&a);
+ ccnxName_Release(&expected);
+ ccnxName_Release(&actual);
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, ccnxName_Create);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, ccnxName_Create)
+{
+ PARCBuffer *value = parcBuffer_WrapCString("Hello");
+
+ for (int i = 0; i < 10000; i++) {
+ CCNxName *name = ccnxName_Create();
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, value);
+ for (int j = 0; j < 1000; j++) {
+ ccnxName_Append(name, segment);
+ }
+ ccnxNameSegment_Release(&segment);
+ ccnxName_Release(&name);
+ }
+ parcBuffer_Release(&value);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_Name);
+ int exitStatus = longBowMain(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_NameLabel.c b/libccnx-common/ccnx/common/test/test_ccnx_NameLabel.c
new file mode 100755
index 00000000..428c2f29
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_NameLabel.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../ccnx_NameLabel.c"
+
+#include <LongBow/unit-test.h>
+#include <stdio.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+
+LONGBOW_TEST_RUNNER(ccnx_NameType)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_NameType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_NameType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameLabel_Create);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameLabel_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameLabel_GetType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameLabel_GetParameter);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameLabel_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameLabel_Copy);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_NULL);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_App0);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_App);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Numeric_Decimal);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Numeric_Hex);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Unknown_Mnemonic);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_BuildString_KnownLabel);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_BuildString_UnknownLabel);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_BuildString_AppLabel);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_BuildString_AppLabel4096);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_DefaultLabel);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_EmptyLabel);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_KnownLabel);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_DecimalParameterLabel);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_HexadecimalParameterLabel);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_OutOfRangeLabel);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_BadHexLabel);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_UknownMnemonicLabel);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic)
+{
+ char *mnemonic = "Name";
+ PARCBuffer *label = parcBuffer_WrapCString(mnemonic);
+ CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label);
+ assertTrue(actual == CCNxNameLabelType_NAME,
+ "Expected an CCNxNameType_NAME type for the mnemonic '%s'", mnemonic);
+ parcBuffer_Release(&label);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_NULL)
+{
+ CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(NULL);
+ assertTrue(actual == CCNxNameLabelType_NAME,
+ "Expected an CCNxNameType_NAME type for a NULL mnemonic.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_Empty)
+{
+ PARCBuffer *label = parcBuffer_Allocate(0);
+ CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label);
+ assertTrue(actual == CCNxNameLabelType_NAME,
+ "Expected an CCNxNameType_NAME type for an empty mnemonic.");
+ parcBuffer_Release(&label);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_App0)
+{
+ PARCBuffer *label = parcBuffer_WrapCString("app");
+ CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label);
+ assertTrue(actual == CCNxNameLabelType_App(0),
+ "Expected 0x%04x type, actual 0x%04x", CCNxNameLabelType_App(0), actual);
+ parcBuffer_Release(&label);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_App)
+{
+ PARCBuffer *label = parcBuffer_WrapCString("app");
+ CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label);
+ assertTrue(actual == CCNxNameLabelType_App(0),
+ "Expected 0x%04x type, actual 0x%04x", CCNxNameLabelType_App(0), actual);
+ parcBuffer_Release(&label);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Numeric_Decimal)
+{
+ PARCBuffer *label = parcBuffer_WrapCString("16");
+ CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label);
+ assertTrue(actual == CCNxNameLabelType_CHUNK,
+ "Expected type %d, actual %d", CCNxNameLabelType_CHUNK, actual);
+ parcBuffer_Release(&label);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Numeric_Hex)
+{
+ CCNxNameLabelType expected = 0xF000;
+ PARCBuffer *label = parcBuffer_WrapCString("0xF000");
+ CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label);
+ assertTrue(actual == expected,
+ "Expected type %d, actual %d", expected, actual);
+ parcBuffer_Release(&label);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Unknown_Mnemonic)
+{
+ CCNxNameLabelType expected = CCNxNameLabelType_Unknown;
+ PARCBuffer *label = parcBuffer_WrapCString("xyzzy");
+ CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label);
+ assertTrue(actual == expected,
+ "Expected type %d, actual %d", expected, actual);
+ parcBuffer_Release(&label);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_BuildString_KnownLabel)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_CHUNK, NULL);
+ ccnxNameLabel_BuildString(label, composer);
+ ccnxNameLabel_Release(&label);
+
+ PARCBuffer *expected = parcBuffer_WrapCString(CCNxNameLabel_Chunk "=");
+ PARCBuffer *actual = parcBuffer_Flip(parcBufferComposer_GetBuffer(composer));
+
+ assertTrue(parcBuffer_Equals(expected, actual),
+ "Expected a successful label lookup.");
+ parcBuffer_Release(&expected);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_BuildString_UnknownLabel)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ CCNxNameLabel *label = ccnxNameLabel_Create(1111, NULL);
+ ccnxNameLabel_BuildString(label, composer);
+ ccnxNameLabel_Release(&label);
+
+ PARCBuffer *expected = parcBuffer_WrapCString("1111" "=");
+ PARCBuffer *actual = parcBuffer_Flip(parcBufferComposer_GetBuffer(composer));
+
+ assertTrue(parcBuffer_Equals(expected, actual),
+ "Expected a successful label lookup.");
+
+ parcBuffer_Release(&expected);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_BuildString_AppLabel)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ PARCBuffer *parameter = parcBuffer_WrapCString("0");
+ CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_App(0), parameter);
+ ccnxNameLabel_BuildString(label, composer);
+ ccnxNameLabel_Release(&label);
+ parcBuffer_Release(&parameter);
+
+ PARCBuffer *expected = parcBuffer_WrapCString("App:0" "=");
+ PARCBuffer *actual = parcBuffer_Flip(parcBufferComposer_GetBuffer(composer));
+
+ assertTrue(parcBuffer_Equals(expected, actual),
+ "Expected a successful label lookup.");
+
+ parcBuffer_Release(&expected);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_BuildString_AppLabel4096)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ PARCBuffer *parameter = parcBuffer_WrapCString("4096");
+ CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_App(4096), parameter);
+ ccnxNameLabel_BuildString(label, composer);
+
+ ccnxNameLabel_Release(&label);
+ parcBuffer_Release(&parameter);
+
+ PARCBuffer *expected = parcBuffer_WrapCString("App:4096" "=");
+ PARCBuffer *actual = parcBuffer_Flip(parcBufferComposer_GetBuffer(composer));
+
+ assertTrue(parcBuffer_Equals(expected, actual),
+ "Expected a successful label lookup.");
+
+ parcBuffer_Release(&expected);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameLabel_GetType)
+{
+ CCNxNameLabelType type = CCNxNameLabelType_NAME;
+ PARCBuffer *parameter = parcBuffer_WrapCString("Hello");
+ CCNxNameLabel *label = ccnxNameLabel_Create(type, parameter);
+
+ CCNxNameLabelType actual = ccnxNameLabel_GetType(label);
+
+ assertTrue(type == actual, "Expected type %u, actual %u", type, actual);
+
+ parcBuffer_Release(&parameter);
+ ccnxNameLabel_Release(&label);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameLabel_GetParameter)
+{
+ CCNxNameLabelType type = CCNxNameLabelType_NAME;
+ PARCBuffer *parameter = parcBuffer_WrapCString("Hello");
+ CCNxNameLabel *label = ccnxNameLabel_Create(type, parameter);
+ PARCBuffer *actual = ccnxNameLabel_GetParameter(label);
+
+ assertTrue(parcBuffer_Equals(parameter, actual), "Expected parameter to be equal to the initial parameter.");
+ parcBuffer_Release(&parameter);
+ ccnxNameLabel_Release(&label);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameLabel_Create)
+{
+ CCNxNameLabelType type = CCNxNameLabelType_NAME;
+ PARCBuffer *parameter = parcBuffer_WrapCString("Hello");
+ CCNxNameLabel *label = ccnxNameLabel_Create(type, parameter);
+ parcBuffer_Release(&parameter);
+ ccnxNameLabel_Release(&label);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameLabel_Copy)
+{
+ PARCBuffer *parameter = parcBuffer_WrapCString("Hello");
+ CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_NAME, parameter);
+ parcBuffer_Release(&parameter);
+
+ CCNxNameLabel *copy = ccnxNameLabel_Copy(label);
+
+ assertTrue(ccnxNameLabel_Equals(label, copy), "Expected copy to the equal to the original.");
+
+ assertTrue(label != copy, "Expected a copy to be distinct from the original.");
+ ccnxNameLabel_Release(&label);
+ ccnxNameLabel_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameLabel_Equals)
+{
+ PARCBuffer *parameter = parcBuffer_WrapCString("Hello");
+ CCNxNameLabel *x = ccnxNameLabel_Create(CCNxNameLabelType_SERIAL, parameter);
+ parcBuffer_Release(&parameter);
+
+ parameter = parcBuffer_WrapCString("Hello");
+ CCNxNameLabel *y = ccnxNameLabel_Create(CCNxNameLabelType_SERIAL, parameter);
+ parcBuffer_Release(&parameter);
+
+ parameter = parcBuffer_WrapCString("Hello");
+ CCNxNameLabel *z = ccnxNameLabel_Create(CCNxNameLabelType_SERIAL, parameter);
+ parcBuffer_Release(&parameter);
+
+ parameter = parcBuffer_WrapCString("Hello");
+ CCNxNameLabel *u1 = ccnxNameLabel_Create(CCNxNameLabelType_CHUNK, parameter);
+ parcBuffer_Release(&parameter);
+
+ parameter = parcBuffer_WrapCString("Goodbye");
+ CCNxNameLabel *u2 = ccnxNameLabel_Create(CCNxNameLabelType_SERIAL, parameter);
+ parcBuffer_Release(&parameter);
+
+ assertEqualsContract(ccnxNameLabel_Equals, x, y, z, u1, u2, NULL);
+
+ ccnxNameLabel_Release(&x);
+ ccnxNameLabel_Release(&y);
+ ccnxNameLabel_Release(&z);
+ ccnxNameLabel_Release(&u1);
+ ccnxNameLabel_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameLabel_AcquireRelease)
+{
+ CCNxNameLabelType type = CCNxNameLabelType_NAME;
+ PARCBuffer *parameter = parcBuffer_WrapCString("Hello");
+ CCNxNameLabel *label = ccnxNameLabel_Create(type, parameter);
+
+ parcObjectTesting_AssertAcquireReleaseContract(ccnxNameLabel_Acquire, label);
+
+ parcBuffer_Release(&parameter);
+ ccnxNameLabel_Release(&label);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Parse)
+{
+ char *expected = "App:1=value";
+ PARCBuffer *buffer = parcBuffer_WrapCString(expected);
+ CCNxNameLabel *label = ccnxNameLabel_Parse(buffer);
+ char *actual = ccnxNameLabel_ToString(label);
+ assertTrue(parcBuffer_Position(buffer) == 6, "Expected position to be 6, actual %zd", parcBuffer_Position(buffer));
+ assertTrue(strcmp("App:1=", actual) == 0, "Expected %s, actual %s", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+ ccnxNameLabel_Release(&label);
+ parcBuffer_Release(&buffer);
+
+ expected = "10:param=value";
+ buffer = parcBuffer_WrapCString(expected);
+ label = ccnxNameLabel_Parse(buffer);
+ actual = ccnxNameLabel_ToString(label);
+ assertTrue(parcBuffer_Position(buffer) == 9, "Expected position to be 9, actual %zd", parcBuffer_Position(buffer));
+ assertTrue(strcmp("10:param=", actual) == 0, "Expected %s, actual %s", "10:param=", actual);
+ parcMemory_Deallocate((void **) &actual);
+ ccnxNameLabel_Release(&label);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_DecimalParameterLabel)
+{
+ char *expected = "10:param=value";
+ PARCBuffer *buffer = parcBuffer_WrapCString(expected);
+ CCNxNameLabel *label = ccnxNameLabel_Parse(buffer);
+ char *actual = ccnxNameLabel_ToString(label);
+ assertTrue(parcBuffer_Position(buffer) == 9, "Expected position to be 9, actual %zd", parcBuffer_Position(buffer));
+ assertTrue(strcmp("10:param=", actual) == 0, "Expected %s, actual %s", "10:param=", actual);
+ parcMemory_Deallocate((void **) &actual);
+ ccnxNameLabel_Release(&label);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_HexadecimalParameterLabel)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("0xaa:param=value");
+ CCNxNameLabel *label = ccnxNameLabel_Parse(buffer);
+ char *actual = ccnxNameLabel_ToString(label);
+ assertTrue(parcBuffer_Position(buffer) == 11, "Expected position to be 11, actual %zd", parcBuffer_Position(buffer));
+ char *expected = "170:param=";
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+ ccnxNameLabel_Release(&label);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_BadHexLabel)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("0xgg:param=value");
+ CCNxNameLabel *label = ccnxNameLabel_Parse(buffer);
+ assertFalse(ccnxNameLabel_IsValid(label), "Expected an invalid CCNxNameLabel from an invalid specification.");
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_OutOfRangeLabel)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("0x123456=value");
+ CCNxNameLabel *label = ccnxNameLabel_Parse(buffer);
+ char *actual = ccnxNameLabel_ToString(label);
+
+ assertTrue(parcBuffer_Position(buffer) == 9, "Expected position to be 9, actual %zd", parcBuffer_Position(buffer));
+ char *expected = "1193046=";
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+ ccnxNameLabel_Release(&label);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_UknownMnemonicLabel)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("abc=value");
+ CCNxNameLabel *label = ccnxNameLabel_Parse(buffer);
+
+ assertFalse(ccnxNameLabel_IsValid(label), "Expected an invalid CCNxNameLabel from an invalid specification.");
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_KnownLabel)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Serial=value");
+ CCNxNameLabel *label = ccnxNameLabel_Parse(buffer);
+ char *actual = ccnxNameLabel_ToString(label);
+ parcMemory_Deallocate((void **) &actual);
+ ccnxNameLabel_Release(&label);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_DefaultLabel)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("value");
+ CCNxNameLabel *label = ccnxNameLabel_Parse(buffer);
+ char *actual = ccnxNameLabel_ToString(label);
+ char *expected = "Name=";
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+ ccnxNameLabel_Release(&label);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_EmptyLabel)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("=value");
+ CCNxNameLabel *label = ccnxNameLabel_Parse(buffer);
+ assertNull(label, "Expected a NULL return value from ccnxNameLabel_Parse for the invalid string '=value'");
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_NameType);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_NameSegment.c b/libccnx-common/ccnx/common/test/test_ccnx_NameSegment.c
new file mode 100644
index 00000000..b691c52a
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_NameSegment.c
@@ -0,0 +1,739 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnx_NameSegment.c"
+
+LONGBOW_TEST_RUNNER(ccnx_NameComponent)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_NameComponent)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_NameComponent)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_CreateTypeValue);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_Copy_WithParameter);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_Length);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_GetType);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ParseURISegment);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_META);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_APP0);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_NAME);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_NAME_NotDefault);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_SERIAL);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_RawNAME);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_APP256);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_PAYLOADHASH);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_NAME);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_META);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_list);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_UnknownLabel);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ZeroLength);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_Compare_Contract);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_Equals_Contract);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_Display);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_IsValid_NULL);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_IsValid_InnerNULL1);
+}
+
+static uint32_t initialAllocationCount;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ initialAllocationCount = parcMemory_Outstanding();
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t remainingAllocations = parcMemory_Outstanding() - initialAllocationCount;
+ if (remainingAllocations > 0) {
+ printf("%s leaks memory by %u allocations\n", longBowTestCase_GetName(testCase), remainingAllocations);
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_IsValid)
+{
+ PARCBuffer *value = parcBuffer_WrapCString("Test");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, value);
+
+ assertTrue(ccnxNameSegment_IsValid(segment), "Expected a valid CCNxNameSegment.");
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&value);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_IsValid_NULL)
+{
+ assertFalse(ccnxNameSegment_IsValid(NULL), "Expected NULL to be an invalid CCNxNameSegment.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_IsValid_InnerNULL1)
+{
+ PARCBuffer *buf = parcBuffer_WrapCString("Test");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf);
+
+ // Hit the NULL case
+ PARCBuffer *oldBuffer = segment->value;
+ segment->value = NULL;
+
+ assertFalse(ccnxNameSegment_IsValid(segment),
+ "Expected a name segment with a NULL value to be invalid.");
+
+ segment->value = oldBuffer;
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_CreateTypeValue)
+{
+ PARCBuffer *buf = parcBuffer_WrapCString("Test");
+
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf);
+ assertNotNull(segment, "Expected non-null");
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_CreateTypeParameterValue)
+{
+ PARCBuffer *parameter = parcBuffer_WrapCString("param");
+ PARCBuffer *value = parcBuffer_WrapCString("Value");
+
+ CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_NAME, parameter);
+ CCNxNameSegment *segment = ccnxNameSegment_CreateLabelValue(label, value);
+ ccnxNameLabel_Release(&label);
+ assertNotNull(segment, "Expected non-null");
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&parameter);
+ parcBuffer_Release(&value);
+}
+
+// Convert the tests to use this table, instead of individual tests.
+struct nameSegments {
+ char *lciSegment;
+ CCNxNameLabelType nameType;
+ char *parameter;
+ char *value;
+} nameSegment[] = {
+ { .lciSegment = "NAME",
+ .nameType = CCNxNameLabelType_NAME, .parameter = NULL, .value = "NAME", },
+ { .lciSegment = CCNxNameLabel_Name "=" "NAME",
+ .nameType = CCNxNameLabelType_NAME, .parameter = NULL, .value = "NAME", },
+ { .lciSegment = CCNxNameLabel_Chunk "=" "Chunk",
+ .nameType = CCNxNameLabelType_CHUNK, .parameter = NULL, .value = "Chunk", },
+ { .lciSegment = CCNxNameLabel_Chunk ":param=" "Chunk",
+ .nameType = CCNxNameLabelType_CHUNK, .parameter = "param", .value = "Chunk", },
+ { .lciSegment = CCNxNameLabel_App ":100=" "app100",
+ .nameType = CCNxNameLabelType_App(100), .parameter = NULL, .value = "app100", },
+ { .lciSegment = NULL },
+};
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_list)
+{
+ for (struct nameSegments *p = &nameSegment[0]; p->lciSegment != NULL; p++) {
+ PARCURISegment *segment = parcURISegment_Parse(p->lciSegment, NULL);
+
+ CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment);
+
+ CCNxNameLabelType type = ccnxNameSegment_GetType(actual);
+ assertTrue(p->nameType == type, "Expected %04x, actual %04x", p->nameType, type);
+
+ PARCBuffer *valueValue = parcBuffer_WrapCString(p->value);
+ PARCBuffer *expectedParam = p->parameter == NULL ? NULL : parcBuffer_WrapCString(p->parameter);
+ CCNxNameLabel *label = ccnxNameLabel_Create(p->nameType, expectedParam);
+ CCNxNameSegment *expected = ccnxNameSegment_CreateLabelValue(label, valueValue);
+ ccnxNameLabel_Release(&label);
+
+ parcBuffer_Release(&valueValue);
+ if (expectedParam != NULL) {
+ parcBuffer_Release(&expectedParam);
+ }
+
+ char *expectedString = ccnxNameSegment_ToString(expected);
+ char *actualString = ccnxNameSegment_ToString(actual);
+ assertTrue(ccnxNameSegment_Equals(expected, actual),
+ "Expected '%s' Actual, '%s", expectedString, actualString);
+ parcMemory_Deallocate((void **) &expectedString);
+ parcMemory_Deallocate((void **) &actualString);
+
+ ccnxNameSegment_Release(&expected);
+ ccnxNameSegment_Release(&actual);
+ parcURISegment_Release(&segment);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_RawNAME)
+{
+ char *lciSegment = "NAME";
+ PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL);
+
+ CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment);
+
+ CCNxNameLabelType type = ccnxNameSegment_GetType(actual);
+ assertTrue(CCNxNameLabelType_NAME == type, "Expected %04x, actual %04x", CCNxNameLabelType_NAME, type);
+
+ PARCBuffer *buf = parcBuffer_WrapCString("NAME");
+ CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf);
+
+ assertTrue(ccnxNameSegment_Equals(expected, actual), "Error in ccnxNameSegment_ParseURISegment")
+ {
+ char *expectedString = ccnxNameSegment_ToString(expected);
+ char *actualString = ccnxNameSegment_ToString(expected);
+ fprintf(stderr, "Expected '%s', actual '%s'", expectedString, actualString);
+ parcMemory_Deallocate((void **) expectedString);
+ parcMemory_Deallocate((void **) actualString);
+ };
+
+ parcBuffer_Release(&buf);
+ ccnxNameSegment_Release(&expected);
+ ccnxNameSegment_Release(&actual);
+ parcURISegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_NAME)
+{
+ char *lciSegment = CCNxNameLabel_Name "=" "NAME";
+ PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL);
+
+ CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment);
+
+ CCNxNameLabelType type = ccnxNameSegment_GetType(actual);
+ assertTrue(CCNxNameLabelType_NAME == type, "Expected %04x, actual %04x", CCNxNameLabelType_NAME, type);
+
+ PARCBuffer *buf = parcBuffer_WrapCString("NAME");
+ CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf);
+
+ assertTrue(ccnxNameSegment_Equals(expected, actual), "Error in ccnxNameSegment_ParseURISegment")
+ {
+ char *expectedString = ccnxNameSegment_ToString(expected);
+ char *actualString = ccnxNameSegment_ToString(expected);
+ fprintf(stderr, "Expected '%s', actual '%s'", expectedString, actualString);
+ parcMemory_Deallocate((void **) expectedString);
+ parcMemory_Deallocate((void **) actualString);
+ };
+
+ ccnxNameSegment_Release(&expected);
+ ccnxNameSegment_Release(&actual);
+ parcURISegment_Release(&segment);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_META)
+{
+ char *lciSegment = CCNxNameLabel_ChunkMeta "=" "META";
+ PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL);
+
+ CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment);
+
+ CCNxNameLabelType type = ccnxNameSegment_GetType(actual);
+ assertTrue(CCNxNameLabelType_CHUNKMETA == type, "Expected 0x%04x, actual 0x%04x", CCNxNameLabelType_CHUNKMETA, type);
+
+ PARCBuffer *buf = parcBuffer_WrapCString("META");
+
+ CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_CHUNKMETA, buf);
+
+ assertTrue(ccnxNameSegment_Equals(expected, actual), "Error in ccnxNameSegment_ParseURISegment")
+ {
+ char *expectedString = ccnxNameSegment_ToString(expected);
+ char *actualString = ccnxNameSegment_ToString(expected);
+ fprintf(stderr, "Expected '%s', actual '%s'", expectedString, actualString);
+ parcMemory_Deallocate((void **) expectedString);
+ parcMemory_Deallocate((void **) actualString);
+ };
+
+ ccnxNameSegment_Release(&expected);
+ ccnxNameSegment_Release(&actual);
+ parcURISegment_Release(&segment);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_UnknownLabel)
+{
+ char *lciSegment = "unknown:param" "=" "abcdef";
+ PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL);
+
+ CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment);
+
+ parcURISegment_Release(&segment);
+
+ assertNull(actual, "Expected NULL return from ccnxNameSegment_ParseURISegment");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_APP0)
+{
+ char *lciSegment = CCNxNameLabelType_LabelApp(0) "=" "APP0";
+ PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL);
+
+ CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment);
+
+ CCNxNameLabelType type = ccnxNameSegment_GetType(actual);
+ assertTrue(CCNxNameLabelType_App(0) == type, "Expected %04x, actual %04x", CCNxNameLabelType_App(0), type);
+
+ PARCBuffer *buf = parcBuffer_WrapCString("APP0");
+
+ CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_App(0), buf);
+ assertTrue(ccnxNameSegment_Equals(expected, actual), "Error in ccnxNameSegment_ParseURISegment")
+ {
+ char *expectedString = ccnxNameSegment_ToString(expected);
+ char *actualString = ccnxNameSegment_ToString(expected);
+ fprintf(stderr, "Expected '%s', actual '%s'", expectedString, actualString);
+ parcMemory_Deallocate((void **) expectedString);
+ parcMemory_Deallocate((void **) actualString);
+ };
+
+ ccnxNameSegment_Release(&expected);
+ ccnxNameSegment_Release(&actual);
+ parcURISegment_Release(&segment);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_APP256)
+{
+ char *lciSegment = CCNxNameLabelType_LabelApp(255) "=" "APP255";
+ PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL);
+
+ CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment);
+
+ CCNxNameLabelType type = ccnxNameSegment_GetType(actual);
+ assertTrue(CCNxNameLabelType_App(255) == type, "Expected %04x, actual %04x", CCNxNameLabelType_App(255), type);
+
+ PARCBuffer *buf = parcBuffer_WrapCString("APP255");
+ CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_App(255), buf);
+ parcBuffer_Release(&buf);
+
+ assertTrue(ccnxNameSegment_Equals(expected, actual), "Error in ccnxNameSegment_ParseURISegment")
+ {
+ char *expectedString = ccnxNameSegment_ToString(expected);
+ char *actualString = ccnxNameSegment_ToString(expected);
+ fprintf(stderr, "Expected '%s', actual '%s'", expectedString, actualString);
+ parcMemory_Deallocate((void **) expectedString);
+ parcMemory_Deallocate((void **) actualString);
+ };
+
+ ccnxNameSegment_Release(&expected);
+ ccnxNameSegment_Release(&actual);
+ parcURISegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment)
+{
+ char *lciSegment = CCNxNameLabel_Name "=" "abcde";
+ PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL);
+
+ CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment);
+
+ CCNxNameLabelType type = ccnxNameSegment_GetType(actual);
+ assertTrue(CCNxNameLabelType_NAME == type,
+ "Expected %04x, actual %04x", 0x20, type);
+
+ PARCBuffer *buf = parcBuffer_WrapCString("abcde");
+
+ CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf);
+
+ assertTrue(ccnxNameSegment_Equals(expected, actual), "Error in ccnxNameSegment_ParseURISegment")
+ {
+ char *expectedString = ccnxNameSegment_ToString(expected);
+ char *actualString = ccnxNameSegment_ToString(expected);
+ fprintf(stderr, "Expected '%s', actual '%s'", expectedString, actualString);
+ parcMemory_Deallocate((void **) expectedString);
+ parcMemory_Deallocate((void **) actualString);
+ };
+
+ ccnxNameSegment_Release(&expected);
+ parcBuffer_Release(&buf);
+ ccnxNameSegment_Release(&actual);
+ parcURISegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ZeroLength)
+{
+ char *begin = "";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(begin);
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer);
+
+ assertNotNull(segment, "Expected non-null");
+ assertTrue(ccnxNameSegment_Length(segment) == 0, "Failed to create a zero length segment");
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_Equals_Contract)
+{
+ PARCBuffer *bufX = parcBuffer_WrapCString("Test");
+ PARCBuffer *bufY = parcBuffer_WrapCString("Test");
+ PARCBuffer *bufZ = parcBuffer_WrapCString("Test");
+ PARCBuffer *bufU1 = parcBuffer_WrapCString("Test");
+ PARCBuffer *bufU2 = parcBuffer_WrapCString("blah");
+
+ CCNxNameSegment *x = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufX);
+ CCNxNameSegment *y = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufY);
+ CCNxNameSegment *z = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufZ);
+ CCNxNameSegment *u1 = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_CHUNKMETA, bufU1);
+ CCNxNameSegment *u2 = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufU2);
+
+ assertEqualsContract(ccnxNameSegment_Equals, x, y, z, u1, u2, NULL);
+
+ ccnxNameSegment_Release(&x);
+ ccnxNameSegment_Release(&y);
+ ccnxNameSegment_Release(&z);
+ ccnxNameSegment_Release(&u1);
+ ccnxNameSegment_Release(&u2);
+
+ parcBuffer_Release(&bufX);
+ parcBuffer_Release(&bufY);
+ parcBuffer_Release(&bufZ);
+ parcBuffer_Release(&bufU1);
+ parcBuffer_Release(&bufU2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_Compare_Contract)
+{
+ char *aString = "foo";
+ PARCBuffer *bufA = parcBuffer_WrapCString(aString);
+ CCNxNameSegment *a = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufA);
+
+ PARCBuffer *bufFoo = parcBuffer_WrapCString("foo");
+ PARCBuffer *bufFon = parcBuffer_WrapCString("fon");
+ PARCBuffer *bufFo = parcBuffer_WrapCString("fo");
+ PARCBuffer *bufFop = parcBuffer_WrapCString("fop");
+ PARCBuffer *bufFooa = parcBuffer_WrapCString("fooa");
+
+ CCNxNameSegment **equivalents = (CCNxNameSegment *[]) {
+ ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufFoo),
+ NULL
+ };
+ CCNxNameSegment **lessers = (CCNxNameSegment *[]) {
+ ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufFon),
+ ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufFo),
+ NULL
+ };
+ CCNxNameSegment **greaters = (CCNxNameSegment *[]) {
+ ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufFop),
+ ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufFooa),
+ NULL
+ };
+
+ assertCompareToContract(ccnxNameSegment_Compare, a, equivalents, lessers, greaters);
+
+ ccnxNameSegment_Release(&a);
+
+ for (int i = 0; equivalents[i] != NULL; i++) {
+ ccnxNameSegment_Release(&equivalents[i]);
+ }
+ for (int i = 0; lessers[i] != NULL; i++) {
+ ccnxNameSegment_Release(&lessers[i]);
+ }
+ for (int i = 0; greaters[i] != NULL; i++) {
+ ccnxNameSegment_Release(&greaters[i]);
+ }
+
+ parcBuffer_Release(&bufFoo);
+ parcBuffer_Release(&bufFon);
+ parcBuffer_Release(&bufFo);
+ parcBuffer_Release(&bufFop);
+ parcBuffer_Release(&bufFooa);
+ parcBuffer_Release(&bufA);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_Length)
+{
+ char *expected = "foo";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(expected);
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer);
+
+ size_t actual = ccnxNameSegment_Length(segment);
+
+ ccnxNameSegment_Release(&segment);
+
+ assertTrue(strlen(expected) == actual,
+ "Expected %zd, actual %zd", strlen(expected), actual);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_Copy)
+{
+ PARCBuffer *buf = parcBuffer_WrapCString("foo");
+ CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf);
+ CCNxNameSegment *actual = ccnxNameSegment_Copy(expected);
+ CCNxNameSegment *acquiredCopy = ccnxNameSegment_Acquire(expected);
+
+ assertTrue(expected != actual, "Expected a distinct copy of the original.");
+
+ char *expectedString = ccnxNameSegment_ToString(expected);
+ char *actualString = ccnxNameSegment_ToString(actual);
+ char *acquiredString = ccnxNameSegment_ToString(acquiredCopy);
+ assertTrue(ccnxNameSegment_Equals(expected, actual), "Expected %s, actual %s", expectedString, actualString);
+ assertTrue(ccnxNameSegment_Equals(expected, acquiredCopy), "Expected %s, actual %s", expectedString, acquiredString);
+
+ parcMemory_Deallocate((void **) &expectedString);
+ parcMemory_Deallocate((void **) &actualString);
+ parcMemory_Deallocate((void **) &acquiredString);
+
+ ccnxNameSegment_Release(&acquiredCopy);
+ ccnxNameSegment_Release(&expected);
+ ccnxNameSegment_Release(&actual);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_Copy_WithParameter)
+{
+ PARCBuffer *value = parcBuffer_WrapCString("value");
+ PARCBuffer *parameter = parcBuffer_WrapCString("param");
+ CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_NAME, parameter);
+ CCNxNameSegment *expected = ccnxNameSegment_CreateLabelValue(label, value);
+ ccnxNameLabel_Release(&label);
+ parcBuffer_Release(&value);
+ parcBuffer_Release(&parameter);
+
+ CCNxNameSegment *actual = ccnxNameSegment_Copy(expected);
+
+ assertTrue(expected != actual, "Expected a distinct copy of the original.");
+
+ char *expectedString = ccnxNameSegment_ToString(expected);
+ char *actualString = ccnxNameSegment_ToString(actual);
+ assertTrue(ccnxNameSegment_Equals(expected, actual), "Expected '%s', actual '%s'", expectedString, actualString);
+
+ parcMemory_Deallocate((void **) &expectedString);
+ parcMemory_Deallocate((void **) &actualString);
+
+ ccnxNameSegment_Release(&expected);
+ ccnxNameSegment_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_GetType)
+{
+ PARCBuffer *buf = parcBuffer_WrapCString("hello");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf);
+
+ assertTrue(CCNxNameLabelType_NAME == ccnxNameSegment_GetType(segment),
+ "Expected type %d, actual %d", CCNxNameLabelType_NAME, ccnxNameSegment_GetType(segment));
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_META)
+{
+ char *expected = CCNxNameLabel_ChunkMeta "=META";
+ PARCBuffer *buf = parcBuffer_WrapCString("META");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_CHUNKMETA, buf);
+ char *actual = ccnxNameSegment_ToString(segment);
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected %s, actual %s", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_PAYLOADHASH)
+{
+ char *expected = CCNxNameLabel_InterestPayloadId "=PAYLOADHASH";
+ PARCBuffer *buf = parcBuffer_WrapCString("PAYLOADHASH");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_PAYLOADID, buf);
+
+ char *actual = ccnxNameSegment_ToString(segment);
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected %s, actual %s", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_NAME)
+{
+ PARCBuffer *buf = parcBuffer_WrapCString("NAME");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf);
+
+ // Note that this is different than the other tests for segments because a NAME name segment
+ // is the default type and as such the string representation doesn't include the leading label specification.
+ char *expected = "NAME";
+ char *actual = ccnxNameSegment_ToString(segment);
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected %s, actual %s", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_NAME_NotDefault)
+{
+ PARCBuffer *value = parcBuffer_WrapCString("MiISAg==");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, value);
+
+ // Note that this is different than the other tests for segments because a NAME name segment
+ // is the default type and as such the string representation doesn't include the leading label specification.
+ char *expected = CCNxNameLabel_Name "=" "MiISAg%3D%3D";
+ char *actual = ccnxNameSegment_ToString(segment);
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected %s, actual %s", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&value);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_APP0)
+{
+ char *expected = CCNxNameLabelType_LabelApp(0) "=APP0";
+ PARCBuffer *buf = parcBuffer_WrapCString("APP0");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_App(0), buf);
+
+ char *actual = ccnxNameSegment_ToString(segment);
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected %s, actual %s", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_SERIAL)
+{
+ char *expected = CCNxNameLabel_Serial "=serialnumber";
+ PARCBuffer *buf = parcBuffer_WrapCString("serialnumber");
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_SERIAL, buf);
+
+ char *actual = ccnxNameSegment_ToString(segment);
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected %s, actual %s", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_APP256)
+{
+ char *expected = CCNxNameLabelType_LabelApp(255) "=APP255";
+ PARCBuffer *buf = parcBuffer_WrapCString("APP255");
+
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_App(255), buf);
+ char *actual = ccnxNameSegment_ToString(segment);
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected %s, actual %s", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_HashCode)
+{
+ PARCBuffer *bufA = parcBuffer_WrapCString("Test");
+
+ CCNxNameSegment *segmentA = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufA);
+ CCNxNameSegment *segmentB = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_CHUNKMETA, bufA);
+
+ assertFalse(ccnxNameSegment_HashCode(segmentA) == ccnxNameSegment_HashCode(segmentB),
+ "Expected different hash codes");
+
+ PARCBuffer *bufC = parcBuffer_WrapCString("Not Test");
+
+ CCNxNameSegment *segmentC = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufC);
+
+ assertFalse(ccnxNameSegment_HashCode(segmentA) == ccnxNameSegment_HashCode(segmentC),
+ "Expected different hash codes");
+
+ CCNxNameSegment *segmentD = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufA);
+
+ assertTrue(ccnxNameSegment_HashCode(segmentD) == ccnxNameSegment_HashCode(segmentA),
+ "Expected same hash codes");
+
+ ccnxNameSegment_Release(&segmentA);
+ ccnxNameSegment_Release(&segmentB);
+ ccnxNameSegment_Release(&segmentC);
+ ccnxNameSegment_Release(&segmentD);
+
+ parcBuffer_Release(&bufA);
+ parcBuffer_Release(&bufC);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegment_Display)
+{
+ PARCBuffer *buf = parcBuffer_WrapCString("Test");
+
+ CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf);
+
+ ccnxNameSegment_Display(segment, 0);
+
+ ccnxNameSegment_Release(&segment);
+ parcBuffer_Release(&buf);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, ccnxNameSegment_AssertValid_Invalid, .event = &LongBowAssertEvent)
+{
+ ccnxNameSegment_AssertValid(NULL);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_NameComponent);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_NameSegmentNumber.c b/libccnx-common/ccnx/common/test/test_ccnx_NameSegmentNumber.c
new file mode 100755
index 00000000..fb14ef39
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_NameSegmentNumber.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../ccnx_NameSegmentNumber.c"
+
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(test_ccnx_NameSegmentNumber)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_ccnx_NameSegmentNumber)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_ccnx_NameSegmentNumber)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create64bits);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create56bits);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create48bits);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create40bits);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create32bits);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create24bits);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create16bits);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create8bits);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_BorderCases);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_IsValid_False);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_AssertValid);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create64bits)
+{
+ uint64_t expected = 0x123456789ABCDEF0;
+ CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+
+ uint64_t actual = ccnxNameSegmentNumber_Value(segment);
+
+ assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual);
+
+ ccnxNameSegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create56bits)
+{
+ uint64_t expected = 0x123456789ABCDE;
+ CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+
+ uint64_t actual = ccnxNameSegmentNumber_Value(segment);
+
+ assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual);
+ ccnxNameSegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create48bits)
+{
+ uint64_t expected = 0x123456789ABC;
+ CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+
+ uint64_t actual = ccnxNameSegmentNumber_Value(segment);
+
+ assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual);
+ ccnxNameSegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create40bits)
+{
+ uint64_t expected = 0x123456789A;
+ CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+
+ uint64_t actual = ccnxNameSegmentNumber_Value(segment);
+
+ assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual);
+ ccnxNameSegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create32bits)
+{
+ uint64_t expected = 0x12345678;
+ CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+
+ uint64_t actual = ccnxNameSegmentNumber_Value(segment);
+
+ assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual);
+ ccnxNameSegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create24bits)
+{
+ uint64_t expected = 0x123456;
+ CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+
+ uint64_t actual = ccnxNameSegmentNumber_Value(segment);
+
+ assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual);
+ ccnxNameSegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create16bits)
+{
+ uint64_t expected = 0x1234;
+ CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+
+ uint64_t actual = ccnxNameSegmentNumber_Value(segment);
+
+ assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual);
+ ccnxNameSegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create8bits)
+{
+ uint64_t expected = 0x12;
+ CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+
+ uint64_t actual = ccnxNameSegmentNumber_Value(segment);
+
+ assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual);
+ ccnxNameSegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_BorderCases)
+{
+ struct test_struct {
+ uint64_t value;
+ size_t length;
+ uint8_t *encoded;
+ } test_vector[] = {
+ { .value = 0x0000000000000000ULL, .length = 1, .encoded = (uint8_t[1]) { 0x00 } },
+ { .value = 0x0000000000000001ULL, .length = 1, .encoded = (uint8_t[1]) { 0x01 } },
+ { .value = 0x00000000000000FFULL, .length = 1, .encoded = (uint8_t[1]) { 0xFF } },
+ { .value = 0x0000000000000100ULL, .length = 2, .encoded = (uint8_t[2]) { 0x01, 0x00} },
+ { .value = 0x0100000000000100ULL, .length = 8, .encoded = (uint8_t[8]) { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00} },
+ { .value = 0x8000000000000100ULL, .length = 8, .encoded = (uint8_t[8]) { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00} },
+ { .value = 0xFFFFFFFFFFFFFFFFULL, .length = 8, .encoded = (uint8_t[8]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} },
+ { .value = 0, .length = 0, .encoded = NULL }
+ };
+
+ for (int i = 0; test_vector[i].encoded != NULL; i++) {
+ PARCBuffer *buffer =
+ parcBuffer_Wrap(test_vector[i].encoded, test_vector[i].length, 0, test_vector[i].length);
+ CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer);
+
+ CCNxNameSegment *actual = ccnxNameSegmentNumber_Create(CCNxNameLabelType_NAME, test_vector[i].value);
+
+ assertTrue(ccnxNameSegment_Equals(expected, actual),
+ "Buffers do not match: test_vector[%d] value %" PRIX64 " Expected %" PRIX64 " actual %" PRIX64 "",
+ i,
+ test_vector[i].value,
+ ccnxNameSegmentNumber_Value(expected),
+ ccnxNameSegmentNumber_Value(actual));
+
+ ccnxNameSegment_Release(&expected);
+ ccnxNameSegment_Release(&actual);
+ parcBuffer_Release(&buffer);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_AssertValid)
+{
+ uint64_t expected = 0x12;
+ CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+
+ ccnxNameSegmentNumber_AssertValid(segment);
+ ccnxNameSegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_IsValid)
+{
+ uint64_t expected = 0x12;
+ CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+
+ assertTrue(ccnxNameSegmentNumber_IsValid(segment), "Expected the CCNxNameSegment to be valid.");
+ ccnxNameSegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_IsValid_False)
+{
+ uint64_t expected = 0x12;
+ CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected);
+
+ PARCBuffer *value = ccnxNameSegment_GetValue(segment);
+ parcBuffer_SetPosition(value, parcBuffer_Limit(value)); // Wreck the buffer by making it zero length.
+
+ assertFalse(ccnxNameSegmentNumber_IsValid(segment), "Expected the CCNxNameSegment to be valid.");
+ ccnxNameSegment_Release(&segment);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_ccnx_NameSegmentNumber);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_TimeStamp.c b/libccnx-common/ccnx/common/test/test_ccnx_TimeStamp.c
new file mode 100755
index 00000000..d65ebd64
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_TimeStamp.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <ccnx/common/ccnx_TimeStamp.c>
+
+#include <inttypes.h>
+#include <time.h>
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+
+LONGBOW_TEST_RUNNER(ccnx_TimeStamp)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(ccnx_TimeStamp)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_TimeStamp)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_CreateFromCurrentUTCTime);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_CreateFromTimespec);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_CreateFromMillisecondsSinceEpoch);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_Equals);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_AsNanoSeconds);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_CreateFromNanosecondsSinceEpoch);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTimeStamp_CreateFromCurrentUTCTime)
+{
+ CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromCurrentUTCTime();
+ assertNotNull(timeStamp, "Expected a non-null response");
+
+ ccnxTimeStamp_Release(&timeStamp);
+ assertNull(timeStamp, "Release failed to NULL the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTimeStamp_CreateFromTimespec)
+{
+ struct timespec time = { .tv_sec = 1, .tv_nsec = 1 };
+
+ CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromTimespec(&time);
+ assertNotNull(timeStamp, "Expected a non-null response");
+
+ struct timespec actualTime = ccnxTimeStamp_AsTimespec(timeStamp);
+
+ assertTrue(time.tv_sec == actualTime.tv_sec && time.tv_nsec == actualTime.tv_nsec, "Expected timespec to be equal.");
+
+ ccnxTimeStamp_Release(&timeStamp);
+ assertNull(timeStamp, "Release failed to NULL the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTimeStamp_CreateFromMillisecondsSinceEpoch)
+{
+ time_t theTimeInSeconds;
+ time(&theTimeInSeconds);
+
+ CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch((uint64_t) theTimeInSeconds * 1000);
+ assertNotNull(timeStamp, "Expected a non-null response");
+
+ struct timespec timeSpec = ccnxTimeStamp_AsTimespec(timeStamp);
+
+ assertTrue(theTimeInSeconds == timeSpec.tv_sec, "Expected %ld, actual %ld", theTimeInSeconds, timeSpec.tv_sec);
+
+ assertTrue(0 == timeSpec.tv_nsec, "Expected %d, actual %ld", 0, timeSpec.tv_nsec);
+
+ ccnxTimeStamp_Release(&timeStamp);
+ assertNull(timeStamp, "Release failed to NULL the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTimeStamp_CreateFromNanosecondsSinceEpoch)
+{
+ uint64_t expected = 1099511627776ULL;
+
+ CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromNanosecondsSinceEpoch(expected);
+
+ uint64_t actual = ccnxTimeStamp_AsNanoSeconds(timeStamp);
+
+ assertTrue(expected == actual, "Expected %" PRIu64 " actual %" PRIu64, expected, actual);
+
+ ccnxTimeStamp_Release(&timeStamp);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTimeStamp_Equals)
+{
+ time_t theTimeInSeconds;
+ time(&theTimeInSeconds);
+
+ CCNxTimeStamp *x = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(theTimeInSeconds * 1000);
+ CCNxTimeStamp *y = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(theTimeInSeconds * 1000);
+ CCNxTimeStamp *z = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(theTimeInSeconds * 1000);
+ CCNxTimeStamp *u1 = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch((theTimeInSeconds + 1) * 1000);
+ CCNxTimeStamp *u2 = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch((theTimeInSeconds + 2) * 1000);
+
+ assertEqualsContract(ccnxTimeStamp_Equals, x, y, z, u1, u2)
+
+ ccnxTimeStamp_Release(&x);
+ ccnxTimeStamp_Release(&y);
+ ccnxTimeStamp_Release(&z);
+ ccnxTimeStamp_Release(&u1);
+ ccnxTimeStamp_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTimeStamp_Copy)
+{
+ time_t theTime;
+ time(&theTime);
+
+ CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(theTime);
+ assertNotNull(timeStamp, "Expected a non-null response");
+
+ CCNxTimeStamp *copy = ccnxTimeStamp_Copy(timeStamp);
+
+ char *expected = ccnxTimeStamp_ToString(timeStamp);
+ char *actual = ccnxTimeStamp_ToString(copy);
+ assertTrue(ccnxTimeStamp_Equals(timeStamp, copy),
+ "Expected %s actual %s.", expected, actual);
+ parcMemory_Deallocate((void **) &expected);
+ parcMemory_Deallocate((void **) &actual);
+
+ ccnxTimeStamp_Release(&timeStamp);
+ ccnxTimeStamp_Release(&copy);
+ assertNull(timeStamp, "Destroy failed to NULL the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTimeStamp_AsNanoSeconds)
+{
+ uint64_t expected = 1099501627776ULL;
+
+ CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromNanosecondsSinceEpoch(expected);
+
+ uint64_t actual = ccnxTimeStamp_AsNanoSeconds(timeStamp);
+
+ assertTrue(expected == actual, "Expected %" PRIu64 " actual %" PRIu64, expected, actual);
+
+ ccnxTimeStamp_Release(&timeStamp);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTimeStamp_ToString)
+{
+ CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromCurrentUTCTime();
+ assertNotNull(timeStamp, "Expected a non-null response");
+
+ char *string = ccnxTimeStamp_ToString(timeStamp);
+ assertNotNull(string, "Expected non-null result.");
+
+ parcMemory_Deallocate((void **) &string);
+
+ ccnxTimeStamp_Release(&timeStamp);
+ assertNull(timeStamp, "Destroy failed to NULL the pointer.");
+ // See case 1016
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_TimeStamp);
+ exit(longBowMain(argc, argv, testRunner, NULL));
+}
diff --git a/libccnx-common/ccnx/common/test/test_ccnx_WireFormatMessage.c b/libccnx-common/ccnx/common/test/test_ccnx_WireFormatMessage.c
new file mode 100755
index 00000000..43b27dc2
--- /dev/null
+++ b/libccnx-common/ccnx/common/test/test_ccnx_WireFormatMessage.c
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Runner.
+#include "../ccnx_WireFormatMessage.c"
+
+#include <stdio.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvPacket.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+
+
+LONGBOW_TEST_RUNNER(ccnx_WireFormatMessage)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_WireFormatMessage)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_WireFormatMessage)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_AssertValid);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_Create);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_FromContentObjectPacketType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_FromControlPacketType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_FromInterestPacketType);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_FromInterestPacketTypeIoVec);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_GetDictionary);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_PutGetIoVec);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_GetWireFormatBuffer);
+ //
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_CreateContentObjectHash);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_HashProtectedRegion);
+ //
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_PutWireFormatBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_SetProtectedRegionLength);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_SetProtectedRegionStart);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_WriteToFile);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_SetHopLimit);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_AcquireRelease)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer);
+
+ CCNxWireFormatMessage *ref = ccnxWireFormatMessage_Acquire(message);
+ assertNotNull(ref, "Expected a non-NULL reference to be acquired");
+
+ ccnxWireFormatMessage_Release(&message);
+ assertNotNull(ref, "Expected a non-NULL reference to be acquired");
+ assertNull(message, "Expeced original message to be NULL");
+
+ ccnxWireFormatMessage_Release(&ref);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_AssertValid)
+{
+ PARCBuffer *wireFormat = parcBuffer_Wrap(v1_interest_nameA, sizeof(v1_interest_nameA), 0, sizeof(v1_interest_nameA));
+
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_Create(wireFormat);
+ assertNotNull(message, "Got null CCNxWireFormatMessage, after attempting to create with buffer");
+
+ ccnxWireFormatMessage_AssertValid(message);
+
+ ccnxWireFormatMessage_Release(&message);
+ parcBuffer_Release(&wireFormat);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_FromContentObjectPacketType)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromContentObjectPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer);
+
+ assertTrue(ccnxTlvDictionary_IsContentObject((CCNxTlvDictionary *) message), "Wrong message type");
+
+ ccnxWireFormatMessage_Release(&message);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_FromControlPacketType)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromControlPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer);
+
+ assertTrue(ccnxTlvDictionary_IsControl((CCNxTlvDictionary *) message), "Wrong message type");
+
+ ccnxWireFormatMessage_Release(&message);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_FromInterestPacketType)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer);
+
+ assertTrue(ccnxTlvDictionary_IsInterest((CCNxTlvDictionary *) message), "Wrong message type");
+
+ ccnxWireFormatMessage_Release(&message);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_Create)
+{
+ PARCBuffer *wireFormat = parcBuffer_Wrap(v1_interest_nameA, sizeof(v1_interest_nameA), 0, sizeof(v1_interest_nameA));
+
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_Create(wireFormat);
+ assertNotNull(message, "Got null CCNxWireFormatMessage, after attempting to create with buffer");
+
+ ccnxWireFormatMessage_Release(&message);
+ parcBuffer_Release(&wireFormat);
+}
+
+/***
+ *** allocator(), deallocator(), createNetworkBufferIoVec() taken from test_ccnx_WireFormatFacadeV1.c
+ ***/
+
+/*
+ * Small size allocator for creating a network buffer
+ */
+static size_t
+_allocator(void *userarg, size_t bytes, void **output)
+{
+ const size_t allocationSize = *(size_t *) userarg;
+ void *allocated = parcMemory_Allocate(allocationSize);
+ *output = allocated;
+ return allocationSize;
+}
+
+/*
+ * deallocator for network buffer
+ */
+static void
+_deallocator(void *userarg, void **memoryPtr)
+{
+ parcMemory_Deallocate(memoryPtr);
+}
+static const CCNxCodecNetworkBufferMemoryBlockFunctions memory = { .allocator = _allocator, .deallocator = _deallocator };
+
+/*
+ * Create a network buffer that looks like this. The actual number of iovecs might
+ * be a little different, but the digest area will span several iovec.
+ *
+ * +-----------+-----------+-----------+-----------+-----------+
+ * iov[0] iov[1] iov[2] iov[3]
+ * +-----------+-----------+-----------+-----------+-----------+
+ * ^ ^
+ * | |
+ * start end
+ */
+static CCNxCodecNetworkBufferIoVec *
+_createNetworkBufferIoVec(size_t allocationSize, size_t padlen, uint8_t pad[padlen], size_t datalen, uint8_t data[datalen])
+{
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&memory, &allocationSize);
+ // build the network buffer
+ ccnxCodecNetworkBuffer_PutArray(netbuff, padlen, pad);
+ ccnxCodecNetworkBuffer_PutArray(netbuff, datalen, data);
+ ccnxCodecNetworkBuffer_PutArray(netbuff, padlen, pad);
+
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+ return vec;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_FromInterestPacketTypeIoVec)
+{
+ uint8_t data[64];
+
+ uint8_t pad[32];
+ CCNxCodecNetworkBufferIoVec *vec = _createNetworkBufferIoVec(512, 32, pad, 64, data);
+
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketTypeIoVec(CCNxTlvDictionary_SchemaVersion_V1, vec);
+
+ assertNotNull(message, "Got null CCNxWireFormatMessage");
+ assertTrue(ccnxTlvDictionary_IsInterest(message), "Wrong message type");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(message) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema, got %d expected %d",
+ ccnxTlvDictionary_GetSchemaVersion(message), CCNxTlvDictionary_SchemaVersion_V1);
+
+ ccnxWireFormatMessage_Release(&message);
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_GetDictionary)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer);
+
+ CCNxTlvDictionary *dictionary = ccnxWireFormatMessage_GetDictionary(message);
+ assertNotNull(dictionary, "Expected to retrieve the dictionary from the CCNxWireFormatMessage");
+ assertTrue(ccnxTlvDictionary_IsInterest(dictionary), "Wrong message type");
+
+ ccnxWireFormatMessage_Release(&message);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_PutGetIoVec)
+{
+ uint8_t *data = parcMemory_Allocate(64);
+ memset(data, 0, 64);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, 64, data);
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+
+ CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxWireFormatMessage_PutIoVec((CCNxWireFormatMessage *) packet, iovec);
+
+ CCNxCodecNetworkBufferIoVec *test = ccnxWireFormatMessage_GetIoVec((CCNxWireFormatMessage *) packet);
+ assertTrue(test == iovec, "Failed to get iovec from dictionary, expected %p got %p", (void *) iovec, (void *) test);
+
+ ccnxTlvDictionary_Release(&packet);
+ parcBuffer_Release(&buffer);
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_GetWireFormatBuffer)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer);
+
+ PARCBuffer *test = ccnxWireFormatMessage_GetWireFormatBuffer(message);
+ assertTrue(test == buffer, "Retrieved unexpected buffer: got %p expected %p", (void *) test, (void *) buffer);
+
+ ccnxWireFormatMessage_Release(&message);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_PutWireFormatBuffer)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ CCNxTlvDictionary *packet = ccnxTlvDictionary_Create(20, 20);
+ ccnxTlvDictionary_SetMessageType_Interest(packet, CCNxTlvDictionary_SchemaVersion_V1);
+ bool success = ccnxWireFormatMessage_PutWireFormatBuffer(packet, buffer);
+
+ assertTrue(success, "Failed to put buffer in to dictionary");
+
+ PARCBuffer *test = ccnxWireFormatMessage_GetWireFormatBuffer(packet);
+ assertTrue(test == buffer, "Retrieved unexpected buffer: got %p expected %p", (void *) test, (void *) buffer);
+
+ ccnxTlvDictionary_Release(&packet);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_HashProtectedRegion)
+{
+ // >1234<
+ const char string[] = "Hello dev null\n";
+
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string));
+ size_t start = 5;
+ size_t length = 4;
+
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromContentObjectPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer);
+
+ ccnxWireFormatMessage_SetProtectedRegionStart(message, start);
+ ccnxWireFormatMessage_SetProtectedRegionLength(message, length);
+
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ PARCCryptoHash *hash = ccnxWireFormatMessage_HashProtectedRegion(message, hasher);
+
+ // the correctness of the has is tested in _ccnxWireFormatFacadeV1_ComputeHash
+ assertNotNull(hash, "Got null hash from a good packet");
+
+ ccnxWireFormatMessage_Release(&message);
+ parcCryptoHash_Release(&hash);
+ parcBuffer_Release(&buffer);
+ parcCryptoHasher_Release(&hasher);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_SetProtectedRegionLength)
+{
+ const char string[] = "Hello dev null\n";
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string));
+
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromContentObjectPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer);
+
+ size_t length = 5;
+ bool success = ccnxWireFormatMessage_SetProtectedRegionLength(message, length);
+ assertTrue(success, "Failed to put integer in to dictionary");
+
+ assertTrue(ccnxTlvDictionary_IsValueInteger(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedLength), "ProtectedLength not set");
+
+ ccnxWireFormatMessage_Release(&message);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_SetProtectedRegionStart)
+{
+ const char string[] = "Hello dev null\n";
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string));
+
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromContentObjectPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer);
+
+ size_t start = 5;
+ bool success = ccnxWireFormatMessage_SetProtectedRegionStart(message, start);
+ assertTrue(success, "Failed to put integer in to dictionary");
+
+ assertTrue(ccnxTlvDictionary_IsValueInteger(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedStart), "ProtectedStart not set");
+
+ ccnxWireFormatMessage_Release(&message);
+ parcBuffer_Release(&buffer);
+}
+
+static PARCBuffer *
+_iovecToParcBuffer(const CCNxCodecNetworkBufferIoVec *iovec)
+{
+ PARCBuffer *result = NULL;
+
+ size_t iovcnt = ccnxCodecNetworkBufferIoVec_GetCount((CCNxCodecNetworkBufferIoVec *) iovec);
+ const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray((CCNxCodecNetworkBufferIoVec *) iovec);
+
+ size_t totalbytes = 0;
+ for (int i = 0; i < iovcnt; i++) {
+ totalbytes += array[i].iov_len;
+ }
+
+ result = parcBuffer_Allocate(totalbytes);
+ for (int i = 0; i < iovcnt; i++) {
+ parcBuffer_PutArray(result, array[i].iov_len, array[i].iov_base);
+ }
+
+ parcBuffer_Flip(result);
+
+
+ return result;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_CreateContentObjectHash)
+{
+ // >1234<
+ const char string[] = "Hello dev null\n";
+
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string));
+
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromContentObjectPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer);
+
+ PARCCryptoHash *hash = ccnxWireFormatMessage_CreateContentObjectHash(message);
+ ccnxWireFormatMessage_Release(&message);
+ assertNull(hash, "Expect NULL for hash as it hasn't been encoded yet");
+
+ // We need to create a content object that is hashable
+ CCNxName *name = ccnxName_CreateFromCString("lci:/test/content");
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, buffer);
+ ccnxName_Release(&name);
+
+ // This next stuff is to force an encode/decode to setup hash extents
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(contentObject, NULL);
+ ccnxContentObject_Release(&contentObject);
+ PARCBuffer *encodedMessage = _iovecToParcBuffer(iovec);
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+ // Decode
+ message = ccnxWireFormatMessage_Create(encodedMessage);
+ CCNxTlvDictionary *dictionary = ccnxWireFormatMessage_GetDictionary(message);
+ bool success = ccnxCodecTlvPacket_BufferDecode(encodedMessage, dictionary);
+ assertTrue(success, "Failed to decode buffer");
+ parcBuffer_Release(&encodedMessage);
+
+ hash = ccnxWireFormatMessage_CreateContentObjectHash(message);
+
+ // the correctness of the hash is tested in _ccnxWireFormatFacadeV1_ComputeHash
+ assertNotNull(hash, "Got null hash from a good packet");
+
+ ccnxWireFormatMessage_Release(&message);
+ parcCryptoHash_Release(&hash);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_WriteToFile)
+{
+ const char string[] = "Hello dev null\n";
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string));
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer);
+
+ ccnxWireFormatMessage_WriteToFile(message, "/dev/null");
+
+ ccnxWireFormatMessage_Release(&message);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_SetHopLimit)
+{
+ uint8_t *data = parcMemory_Allocate(64);
+ memset(data, 0, 64);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, 64, data);
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+
+ CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest();
+ ccnxWireFormatMessage_PutIoVec((CCNxWireFormatMessage *) packet, iovec);
+
+ ccnxWireFormatMessage_SetHopLimit(packet, 10);
+
+ CCNxCodecNetworkBufferIoVec *test = ccnxWireFormatMessage_GetIoVec((CCNxWireFormatMessage *) packet);
+ assertTrue(test == iovec, "Failed to get iovec from dictionary, expected %p got %p", (void *) iovec, (void *) test);
+
+ ccnxTlvDictionary_Release(&packet);
+ parcBuffer_Release(&buffer);
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+}
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _getImplForSchema);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxWireFormatMessage_CreateWithImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxWireFormatMessage_CreateWithImpl)
+{
+ PARCBuffer *wireFormatV1 = parcBuffer_Wrap(v1_interest_nameA, sizeof(v1_interest_nameA), 0, sizeof(v1_interest_nameA));
+
+ CCNxWireFormatMessage *message = _ccnxWireFormatMessage_CreateWithImpl(&CCNxWireFormatFacadeV1_Implementation, wireFormatV1);
+ assertNotNull(message, "Expected to create a V1 CCNxWireFormatMessage");
+
+ ccnxWireFormatMessage_Release(&message);
+ parcBuffer_Release(&wireFormatV1);
+}
+
+LONGBOW_TEST_CASE(Static, _getImplForSchema)
+{
+ CCNxWireFormatMessageInterface *impl = _getImplForSchema(CCNxTlvDictionary_SchemaVersion_V1);
+ assertTrue(impl = &CCNxWireFormatFacadeV1_Implementation, "Expected to see CCNxWireFormatFacadeV1_Implementation");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_WireFormatMessage);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/validation/ccnxValidation_CRC32C.c b/libccnx-common/ccnx/common/validation/ccnxValidation_CRC32C.c
new file mode 100644
index 00000000..f8ff7ba4
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/ccnxValidation_CRC32C.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * See SCTP for a discussion of CRC32C http://tools.ietf.org/html/rfc4960#appendix-B
+ * It is also used by iSCSI and other protocols.
+ *
+ * CRC-32C uses an initial value of 0xFFFFFFFF and a final XOR value of 0xFFFFFFFF.
+ *
+ */
+#include <config.h>
+#include <stdio.h>
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_CryptoHasher.h>
+
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+typedef struct crc32_signer {
+ PARCCryptoHasher *hasher;
+} _CRC32Signer;
+
+typedef struct crc32_verifier {
+ PARCCryptoHasher *hasher;
+} _CRC32Verifier;
+
+bool
+ccnxValidationCRC32C_Set(CCNxTlvDictionary *message)
+{
+ bool success = true;
+ switch (ccnxTlvDictionary_GetSchemaVersion(message)) {
+ case CCNxTlvDictionary_SchemaVersion_V1: {
+ success &= ccnxTlvDictionary_PutInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, PARCCryptoSuite_NULL_CRC32C);
+
+ break;
+ }
+
+ default:
+ trapIllegalValue(message, "Unknown schema version: %d", ccnxTlvDictionary_GetSchemaVersion(message));
+ }
+ return success;
+}
+
+bool
+ccnxValidationCRC32C_Test(const CCNxTlvDictionary *message)
+{
+ switch (ccnxTlvDictionary_GetSchemaVersion(message)) {
+ case CCNxTlvDictionary_SchemaVersion_V1: {
+ if (ccnxTlvDictionary_IsValueInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE)) {
+ uint64_t cryptosuite = ccnxTlvDictionary_GetInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ return (cryptosuite == PARCCryptoSuite_NULL_CRC32C);
+ }
+ return false;
+ }
+
+ default:
+ trapIllegalValue(message, "Unknown schema version: %d", ccnxTlvDictionary_GetSchemaVersion(message));
+ }
+ return false;
+}
+
+static bool
+_crc32cSigner_Destructor(_CRC32Signer **interfaceContextPtr)
+{
+ _CRC32Signer *signer = *interfaceContextPtr;
+ parcCryptoHasher_Release(&signer->hasher);
+ return true;
+}
+
+parcObject_ImplementAcquire(_crc32CSigner, _CRC32Signer);
+parcObject_ImplementRelease(_crc32CSigner, _CRC32Signer);
+
+parcObject_Override(_CRC32Signer, PARCObject,
+ .destructor = (PARCObjectDestructor *) _crc32cSigner_Destructor);
+
+static bool
+_crc32Verifier_Destructor(_CRC32Verifier **verifierPtr)
+{
+ _CRC32Verifier *verifier = (_CRC32Verifier *) *verifierPtr;
+
+ parcCryptoHasher_Release(&(verifier->hasher));
+ return true;
+}
+
+parcObject_ImplementAcquire(_crc32Verifier, _CRC32Verifier);
+parcObject_ImplementRelease(_crc32Verifier, _CRC32Verifier);
+
+parcObject_Override(_CRC32Verifier, PARCObject,
+ .destructor = (PARCObjectDestructor *) _crc32Verifier_Destructor);
+
+static PARCSignature *
+_crc32Signer_SignDigest(_CRC32Signer *interfaceContext, const PARCCryptoHash *cryptoHash)
+{
+ PARCSignature *signature =
+ parcSignature_Create(PARCSigningAlgortihm_NULL, PARCCryptoHashType_CRC32C, parcCryptoHash_GetDigest(cryptoHash));
+ return signature;
+}
+
+static PARCSigningAlgorithm
+_crc32Signer_GetSigningAlgorithm(_CRC32Signer *interfaceContext)
+{
+ return PARCSigningAlgortihm_NULL;
+}
+
+static PARCCryptoHashType
+_crc32Signer_GetCryptoHashType(_CRC32Signer *interfaceContext)
+{
+ return PARCCryptoHashType_CRC32C;
+}
+
+static PARCCryptoHasher *
+_crc32Signer_GetCryptoHasher(_CRC32Signer *signer)
+{
+ return signer->hasher;
+}
+
+static PARCCryptoHasher *
+_crc32Verifier_GetCryptoHasher(_CRC32Verifier *verifier, PARCKeyId *keyid, PARCCryptoHashType hashType)
+{
+ assertTrue(hashType == PARCCryptoHashType_CRC32C, "Only supports PARCCryptoHashType_CRC32C, got request for %s", parcCryptoHashType_ToString(hashType));
+
+ return verifier->hasher;
+}
+
+static bool
+_crc32Verifier_VerifyDigest(_CRC32Verifier *verifier, PARCKeyId *keyid, PARCCryptoHash *locallyComputedHash,
+ PARCCryptoSuite suite, PARCSignature *signatureToVerify)
+{
+ assertTrue(suite == PARCCryptoSuite_NULL_CRC32C, "Only supports PARC_SUITE_NULL_CRC32C, got request for %d", suite);
+
+ PARCBuffer *calculatedCrc = parcCryptoHash_GetDigest(locallyComputedHash);
+
+ // the signature is the CRC, so we just need to compare to the to calculated CRC32C "hash"
+ PARCBuffer *crcToVerify = parcSignature_GetSignature(signatureToVerify);
+
+ return parcBuffer_Equals(calculatedCrc, crcToVerify);
+}
+
+static bool
+_crc32Verifier_AllowedCryptoSuite(_CRC32Verifier *verifier, PARCKeyId *keyid, PARCCryptoSuite suite)
+{
+ return (suite == PARCCryptoSuite_NULL_CRC32C);
+}
+
+PARCSigningInterface *CRC32SignerAsPARCSigner = &(PARCSigningInterface) {
+ .GetCryptoHasher = (PARCCryptoHasher * (*)(void *))_crc32Signer_GetCryptoHasher,
+ .SignDigest = (PARCSignature * (*)(void *, const PARCCryptoHash *))_crc32Signer_SignDigest,
+ .GetSigningAlgorithm = (PARCSigningAlgorithm (*)(void *))_crc32Signer_GetSigningAlgorithm,
+ .GetCryptoHashType = (PARCCryptoHashType (*)(void *))_crc32Signer_GetCryptoHashType
+};
+
+PARCVerifierInterface *CRC32VerifierAsPARCVerifier = &(PARCVerifierInterface) {
+ .GetCryptoHasher = (PARCCryptoHasher * (*)(void *, PARCKeyId *, PARCCryptoHashType))_crc32Verifier_GetCryptoHasher,
+ .VerifyDigest = (bool (*)(void *, PARCKeyId *, PARCCryptoHash *, PARCCryptoSuite, PARCSignature *))_crc32Verifier_VerifyDigest,
+ .AddKey = NULL,
+ .RemoveKeyId = NULL,
+ .AllowedCryptoSuite = (bool (*)(void *, PARCKeyId *, PARCCryptoSuite))_crc32Verifier_AllowedCryptoSuite,
+};
+
+static PARCSigner *
+_crc32Signer_Create(void)
+{
+ _CRC32Signer *crc32Signer = parcObject_CreateInstance(_CRC32Signer);
+ assertNotNull(crc32Signer, "parcObject_CreateInstance returned NULL");
+
+ crc32Signer->hasher = parcCryptoHasher_Create(PARCCryptoHashType_CRC32C);
+ PARCSigner *signer = parcSigner_Create(crc32Signer, CRC32SignerAsPARCSigner);
+ _crc32CSigner_Release(&crc32Signer);
+
+ return signer;
+}
+
+PARCSigner *
+ccnxValidationCRC32C_CreateSigner(void)
+{
+ return _crc32Signer_Create();
+}
+
+static PARCVerifier *
+_crc32Verifier_Create(void)
+{
+ _CRC32Verifier *crcVerifier = parcObject_CreateInstance(_CRC32Verifier);
+ assertNotNull(crcVerifier, "parcObject_CreateInstance returned NULL");
+
+ crcVerifier->hasher = parcCryptoHasher_Create(PARCCryptoHashType_CRC32C);
+
+ PARCVerifier *verifier = parcVerifier_Create(crcVerifier, CRC32VerifierAsPARCVerifier);
+ _crc32Verifier_Release(&crcVerifier);
+
+ return verifier;
+}
+
+PARCVerifier *
+ccnxValidationCRC32C_CreateVerifier(void)
+{
+ return _crc32Verifier_Create();
+}
diff --git a/libccnx-common/ccnx/common/validation/ccnxValidation_CRC32C.h b/libccnx-common/ccnx/common/validation/ccnxValidation_CRC32C.h
new file mode 100755
index 00000000..4d26015a
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/ccnxValidation_CRC32C.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxValidation_CRC32C.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef CCNx_Common_ccnxValidation_CRC32C_h
+#define CCNx_Common_ccnxValidation_CRC32C_h
+
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_Verifier.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+/**
+ * Sets the Validation algorithm to RSA-SHA256
+ *
+ * Sets the validation algorithm to be RSA with a SHA-256 digest. Optionally includes
+ * a KeyId and KeyLocator with the message.
+ *
+ * @param [in] message The message dictionary
+ *
+ * @return `true` success
+ * @return `false` failure
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxValidationCRC32C_Set(CCNxTlvDictionary *message);
+
+/**
+ * Determines if the validation algorithm is RSA-SHA256 *
+ * @param [in] message The message to check
+ *
+ * @return `true` The validation algorithm in the dictionary is this one
+ * @return `false` The validaiton algorithm in the dictionary is something else or not present
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxValidationCRC32C_Test(const CCNxTlvDictionary *message);
+
+/**
+ * Creates a signer to compute a CRC32C
+ *
+ * @return non-null An allocated signer
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSigner *ccnxValidationCRC32C_CreateSigner(void);
+
+/**
+ * Creates a verifier to check a CRC32C "signature"
+ *
+ * @return non-null An allocated verifier
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVerifier *ccnxValidationCRC32C_CreateVerifier(void);
+#endif // CCNx_Common_ccnxValidation_CRC32C_h
diff --git a/libccnx-common/ccnx/common/validation/ccnxValidation_EcSecp256K1.c b/libccnx-common/ccnx/common/validation/ccnxValidation_EcSecp256K1.c
new file mode 100755
index 00000000..d40a8378
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/ccnxValidation_EcSecp256K1.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+// ========================================================================================
+
+/**
+ * Sets the Validation algorithm to EC-SECP-256K1
+ *
+ * Sets the validation algorithm to be Elliptical Curve with SECP-256K1 parameters. Optionally includes
+ * a KeyId and KeyLocator with the message.
+ *
+ * @param [in] message The message dictionary
+ * @param [in] keyid (Optional) The KEYID to include the the message
+ * @param [in] keyLocator (Optional) The KEY LOCATOR to include in the message
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool
+ccnxValidationEcSecp256K1_Set(CCNxTlvDictionary *message, const PARCBuffer *keyid, const CCNxKeyLocator *keyLocator)
+{
+ bool success = true;
+ switch (ccnxTlvDictionary_GetSchemaVersion(message)) {
+ case CCNxTlvDictionary_SchemaVersion_V1: {
+ success &= ccnxTlvDictionary_PutInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, PARCCryptoSuite_EC_SECP_256K1);
+
+ if (keyid) {
+ success &= ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID, keyid);
+ }
+
+ success &= ccnxValidationFacadeV1_SetKeyLocator(message, (CCNxKeyLocator *) keyLocator); // un-consting
+
+ break;
+ }
+
+ default:
+ trapIllegalValue(message, "Unknown schema version: %d", ccnxTlvDictionary_GetSchemaVersion(message));
+ }
+ return success;
+}
+
+bool
+ccnxValidationEcSecp256K1_Test(const CCNxTlvDictionary *message)
+{
+ if (ccnxTlvDictionary_IsValueInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE)) {
+ uint64_t cryptosuite = ccnxTlvDictionary_GetInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ return (cryptosuite == PARCCryptoSuite_EC_SECP_256K1);
+ }
+ return false;
+}
diff --git a/libccnx-common/ccnx/common/validation/ccnxValidation_EcSecp256K1.h b/libccnx-common/ccnx/common/validation/ccnxValidation_EcSecp256K1.h
new file mode 100755
index 00000000..3c949769
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/ccnxValidation_EcSecp256K1.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxValidation_EcSecp256K1.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef CCNx_Common_ccnxValidation_EcSecp256K1_h
+#define CCNx_Common_ccnxValidation_EcSecp256K1_h
+
+#include <stdbool.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+#include <ccnx/common/ccnx_KeyLocator.h>
+
+/**
+ *
+ * Sets the validation algorithm to be Elliptical Curve with SECP-256K1 parameters.
+ * Optionally includes a KeyId and KeyLocator with the message.
+ *
+ * @param [in] message The message dictionary
+ * @param [in] keyid (Optional) The KEYID to include the the message
+ * @param [in] keyLocator (Optional) The KEY LOCATOR to include in the message
+ *
+ * @return true success
+ * @return false failure
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxValidationEcSecp256K1_Set(CCNxTlvDictionary *message, const PARCBuffer *keyid, const CCNxKeyLocator *keyLocator);
+
+/**
+ * Determines if the validation algorithm is Elliptical Curve with SECP-256K1 parameters.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] message The message to check
+ *
+ * @return true The validation algorithm in the dictionary is this one
+ * @return false The validaiton algorithm in the dictionary is something else or not present
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxValidationEcSecp256K1_Test(const CCNxTlvDictionary *message);
+
+/**
+ * Returns the KeyId associated with the validation algorithm
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] message The message to check
+ *
+ * @return non-NULL the keyid
+ * @return null An error or no keyid or no validation algorithm in the message
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *ccnxValidationEcSecp256K1_GetKeyId(const CCNxTlvDictionary *message);
+
+/**
+ * Returns the KeyName associated with the validation algorithm
+ *
+ * This should return a LINK, see case 1018
+ *
+ * @param [in] message The message to check
+ *
+ * @return non-NULL the KeyName
+ * @return null An error or no keyid or no validation algorithm in the message
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxName *ccnxValidationEcSecp256K1_GetKeyLocatorName(const CCNxTlvDictionary *message);
+
+/**
+ * Returns the PublicKey associated with the validation algorithm
+ *
+ * @param [in] message The message to check
+ *
+ * @return non-NULL the PublicKey (DER encoded)
+ * @return null An error or no public key or no validation algorithm in the message
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *ccnxValidationEcSecp256K1_GetKeyLocatorPublicKey(const CCNxTlvDictionary *message);
+
+/**
+ * Returns the Certificate associated with the validation algorithm
+ *
+ * @param [in] message The message to check
+ *
+ * @return non-NULL the Certificate (DER encoded)
+ * @return null An error or no certificate or no validation algorithm in the message
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *ccnxValidationEcSecp256K1_GetKeyLocatorCertificate(const CCNxTlvDictionary *message);
+#endif // CCNx_Common_ccnxValidation_EcSecp256K1_h
diff --git a/libccnx-common/ccnx/common/validation/ccnxValidation_HmacSha256.c b/libccnx-common/ccnx/common/validation/ccnxValidation_HmacSha256.c
new file mode 100644
index 00000000..5202508e
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/ccnxValidation_HmacSha256.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+#include <parc/security/parc_Verifier.h>
+#include <parc/security/parc_SymmetricKeyStore.h>
+#include <parc/security/parc_SymmetricKeySigner.h>
+
+/**
+ * Sets the Validation algorithm to HMAC with SHA-256 hash
+ *
+ * Sets the validation algorithm to be HMAC with a SHA-256 digest. Optionally includes
+ * a KeyId with the message.
+ *
+ * @param [in] message The message dictionary
+ * @param [in] keyid (Optional) The KEYID to include the the message
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool
+ccnxValidationHmacSha256_Set(CCNxTlvDictionary *message, const PARCBuffer *keyid)
+{
+ bool success = true;
+ switch (ccnxTlvDictionary_GetSchemaVersion(message)) {
+ case CCNxTlvDictionary_SchemaVersion_V1: {
+ success &= ccnxTlvDictionary_PutInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, PARCCryptoSuite_HMAC_SHA256);
+
+ if (keyid) {
+ success &= ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID, keyid);
+ }
+
+ break;
+ }
+
+ default:
+ trapIllegalValue(message, "Unknown schema version: %d", ccnxTlvDictionary_GetSchemaVersion(message));
+ }
+ return success;
+}
+
+bool
+ccnxValidationHmacSha256_Test(const CCNxTlvDictionary *message)
+{
+ switch (ccnxTlvDictionary_GetSchemaVersion(message)) {
+ case CCNxTlvDictionary_SchemaVersion_V1: {
+ if (ccnxTlvDictionary_IsValueInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE)) {
+ uint64_t cryptosuite = ccnxTlvDictionary_GetInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ return (cryptosuite == PARCCryptoSuite_HMAC_SHA256);
+ }
+ return false;
+ }
+
+ default:
+ trapIllegalValue(message, "Unknown schema version: %d", ccnxTlvDictionary_GetSchemaVersion(message));
+ }
+ return false;
+}
+
+PARCSigner *
+ccnxValidationHmacSha256_CreateSigner(PARCBuffer *secretKey)
+{
+ PARCSymmetricKeyStore *keyStore = parcSymmetricKeyStore_Create(secretKey);
+ PARCSymmetricKeySigner *symmetricSigner = parcSymmetricKeySigner_Create(keyStore, PARCCryptoHashType_SHA256);
+ parcSymmetricKeyStore_Release(&keyStore);
+
+ PARCSigner *signer = parcSigner_Create(symmetricSigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&symmetricSigner);
+
+ return signer;
+}
+
+PARCVerifier *
+ccnxValidationHmacSha256_CreateVerifier(PARCBuffer *secretKey)
+{
+ trapNotImplemented("not finished yet");
+}
diff --git a/libccnx-common/ccnx/common/validation/ccnxValidation_HmacSha256.h b/libccnx-common/ccnx/common/validation/ccnxValidation_HmacSha256.h
new file mode 100755
index 00000000..94f6af75
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/ccnxValidation_HmacSha256.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxValidation_HmacSha256.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef CCNx_Common_ccnxValidation_HmacSha256_h
+#define CCNx_Common_ccnxValidation_HmacSha256_h
+
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_Verifier.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+/**
+ * Sets the Validation algorithm to HMAC-SHA256
+ *
+ * Sets the validation algorithm to be HMAC with a SHA-256 digest. Optionally includes a KeyId
+ *
+ * @param [in] message The message dictionary
+ * @param [in] keyid (Optional) The KEYID to include the the message
+ *
+ * @return true success
+ * @return false failure
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxValidationHmacSha256_Set(CCNxTlvDictionary *message, const PARCBuffer *keyid);
+
+/**
+ * Determines if the validation algorithm is RSA-SHA256
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] message The message to check
+ *
+ * @return true The validation algorithm in the dictionary is this one
+ * @return false The validaiton algorithm in the dictionary is something else or not present
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxValidationHmacSha256_Test(const CCNxTlvDictionary *message);
+
+/**
+ * Creates a signer using a specified secret key
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] secretKey The key to use as the authenticator
+ *
+ * @return non-null An allocated signer
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSigner *ccnxValidationHmacSha256_CreateSigner(PARCBuffer *secretKey);
+
+/**
+ * Creates a verifier to check a CRC32C "signature"
+ *
+ * Once the Verifier is created, you can add more keys using
+ * parcVerifier_AddKey(). If you provide a secretKey in the call, it will
+ * be added to the verifier automatically.
+ *
+ * @param [in] secretKey (Optional) The key to use as the authenticator, or NULL.
+ *
+ * @return non-null An allocated verifier
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVerifier *ccnxValidationHmacSha256_CreateVerifier(PARCBuffer *secretKey);
+#endif // CCNx_Common_ccnxValidation_HmacSha256_h
diff --git a/libccnx-common/ccnx/common/validation/ccnxValidation_RsaSha256.c b/libccnx-common/ccnx/common/validation/ccnxValidation_RsaSha256.c
new file mode 100644
index 00000000..39590a9d
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/ccnxValidation_RsaSha256.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+// ========================================================================================
+
+bool
+ccnxValidationRsaSha256_Set(CCNxTlvDictionary *message, const PARCBuffer *keyid, const CCNxKeyLocator *keyLocator)
+{
+ bool success = true;
+ success &= ccnxTlvDictionary_PutInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, PARCCryptoSuite_RSA_SHA256);
+
+ if (keyid) {
+ success &= ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID, keyid);
+ }
+
+ success &= ccnxValidationFacadeV1_SetKeyLocator(message, (CCNxKeyLocator *) keyLocator); // un-consting
+
+ return success;
+}
+
+bool
+ccnxValidationRsaSha256_Test(const CCNxTlvDictionary *message)
+{
+ if (ccnxTlvDictionary_IsValueInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE)) {
+ uint64_t cryptosuite = ccnxTlvDictionary_GetInteger(message, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ return (cryptosuite == PARCCryptoSuite_RSA_SHA256);
+ }
+ return false;
+}
diff --git a/libccnx-common/ccnx/common/validation/ccnxValidation_RsaSha256.h b/libccnx-common/ccnx/common/validation/ccnxValidation_RsaSha256.h
new file mode 100755
index 00000000..f1835dca
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/ccnxValidation_RsaSha256.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ccnxValidation_RsaSha256.h
+ * @brief <#Brief Description#>
+ *
+ * The RsaSha256 validation algorithm uses standard locations for KeyId, PublicKey, Certificate, and KeyName,
+ * so you should use ccnxValidationFacade getters to retrieve them.
+ *
+ */
+#ifndef CCNx_Common_ccnxValidation_RsaSha256_h
+#define CCNx_Common_ccnxValidation_RsaSha256_h
+
+#include <stdbool.h>
+#include <parc/algol/parc_Buffer.h>
+#include <ccnx/common/ccnx_KeyLocator.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+/**
+ * Sets the Validation algorithm to RSA-SHA256
+ *
+ * Sets the validation algorithm to be RSA with a SHA-256 digest. Optionally includes
+ * a KeyId and KeyLocator with the message.
+ *
+ * @param [in] message The message dictionary
+ * @param [in] keyid (Optional) The KEYID to include the the message
+ * @param [in] keyLocator (Optional) The KEY LOCATOR to include in the message
+ *
+ * @return true success
+ * @return false failure
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxValidationRsaSha256_Set(CCNxTlvDictionary *message, const PARCBuffer *keyid, const CCNxKeyLocator *keyLocator);
+
+/**
+ * Determines if the validation algorithm is RSA-SHA256
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] message The message to check
+ *
+ * @return true The validation algorithm in the dictionary is this one
+ * @return false The validaiton algorithm in the dictionary is something else or not present
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxValidationRsaSha256_Test(const CCNxTlvDictionary *message);
+#endif // CCNx_Common_ccnxValidation_RsaSha256_h
diff --git a/libccnx-common/ccnx/common/validation/test/.gitignore b/libccnx-common/ccnx/common/validation/test/.gitignore
new file mode 100644
index 00000000..d5f2004f
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/test/.gitignore
@@ -0,0 +1,4 @@
+test_ccnxValidation_CRC32C
+test_ccnxValidation_EcSecp256K1
+test_ccnxValidation_HmacSha256
+test_ccnxValidation_RsaSha256
diff --git a/libccnx-common/ccnx/common/validation/test/CMakeLists.txt b/libccnx-common/ccnx/common/validation/test/CMakeLists.txt
new file mode 100644
index 00000000..90f678f7
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/test/CMakeLists.txt
@@ -0,0 +1,16 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_ccnxValidation_CRC32C
+ test_ccnxValidation_EcSecp256K1
+ test_ccnxValidation_HmacSha256
+ test_ccnxValidation_RsaSha256
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-common/ccnx/common/validation/test/test_ccnxValidation_CRC32C.c b/libccnx-common/ccnx/common/validation/test/test_ccnxValidation_CRC32C.c
new file mode 100755
index 00000000..90eae917
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/test/test_ccnxValidation_CRC32C.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxValidation_CRC32C.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+#include "testrig_validation.c"
+
+#include <sys/time.h>
+
+/*
+ * Ground truth set derived from CRC RevEng http://reveng.sourceforge.net
+ * e.g. reveng -c -m CRC-32C 313233343536373839 gives the canonical check value 0xe306928e
+ *
+ * You can also calcaulate them online at http://www.zorc.breitbandkatze.de/crc.html using
+ * CRC polynomial 0x1EDC6F41, init 0xFFFFFFFF, final 0xFFFFFFFF, reverse data bytes (check),
+ * and reverse CRC result before final XOR (check).
+ *
+ */
+struct test_vector {
+ uint32_t crc32c;
+ int length;
+ uint8_t *buffer;
+} vectors[] = {
+ { .crc32c = 0xe3069283, .length = 9, .buffer = (uint8_t []) { '1', '2', '3', '4', '5', '6', '7', '8', '9' } },
+ { .crc32c = 0xddb65633, .length = 1, .buffer = (uint8_t []) { 0x3D } },
+ { .crc32c = 0xc203c1fd, .length = 2, .buffer = (uint8_t []) { 0x3D, 0x41 } },
+ { .crc32c = 0x80a9d169, .length = 3, .buffer = (uint8_t []) { 'b', 'e', 'e' } },
+ { .crc32c = 0xa099f534, .length = 4, .buffer = (uint8_t []) { 'h', 'e', 'l', 'l' } },
+ { .crc32c = 0x9a71bb4c, .length = 5, .buffer = (uint8_t []) { 'h', 'e', 'l', 'l', 'o' } },
+ { .crc32c = 0x2976E503, .length = 6, .buffer = (uint8_t []) { 'g', 'r', 'u', 'm', 'p', 'y' } },
+ { .crc32c = 0xe627f441, .length = 7, .buffer = (uint8_t []) { 'a', 'b', 'c', 'd', 'e', 'f', 'g' } },
+ { .crc32c = 0x2d265c1d, .length = 13, .buffer = (uint8_t []) { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'c', 'd', 'e', 'f'} },
+ { .crc32c = 0, .length = 0, .buffer = NULL }
+};
+
+LONGBOW_TEST_RUNNER(ccnxValidation_CRC32C)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxValidation_CRC32C)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxValidation_CRC32C)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ===========================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxValidationCRC32C_Set);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxValidationCRC32C_CreateSigner);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxValidationCRC32C_CreateVerifier);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxValidationCRC32C_DictionaryCryptoSuiteValue);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxValidationCRC32C_Set)
+{
+ // do not test on V0 packets, no support
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testValidationSet_NoParam(data, ccnxValidationCRC32C_Set, ccnxValidationCRC32C_Test, false, true);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxValidationCRC32C_CreateSigner)
+{
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ assertNotNull(signer, "Got null signer");
+
+ // now run all the test vectors through it
+
+ for (int i = 0; vectors[i].buffer != NULL; i++) {
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, vectors[i].buffer, vectors[i].length);
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+
+ PARCSignature *sig = parcSigner_SignDigest(signer, hash);
+ PARCBuffer *sigbits = parcSignature_GetSignature(sig);
+ uint32_t testCrc = parcBuffer_GetUint32(sigbits);
+ assertTrue(testCrc == vectors[i].crc32c,
+ "CRC32C values wrong, index %d got 0x%08x expected 0x%08x\n",
+ i, testCrc, vectors[i].crc32c);
+
+ parcSignature_Release(&sig);
+ parcCryptoHash_Release(&hash);
+ }
+
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxValidationCRC32C_CreateVerifier)
+{
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner();
+ assertNotNull(signer, "Got null signer");
+
+ PARCVerifier *verifier = ccnxValidationCRC32C_CreateVerifier();
+ assertNotNull(verifier, "Got null verifier");
+
+ for (int i = 0; vectors[i].buffer != NULL; i++) {
+ // Produce the signature
+ PARCSignature *sig = NULL;
+ {
+ PARCCryptoHasher *signingHasher = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(signingHasher);
+ parcCryptoHasher_UpdateBytes(signingHasher, vectors[i].buffer, vectors[i].length);
+ PARCCryptoHash *signingHash = parcCryptoHasher_Finalize(signingHasher);
+ sig = parcSigner_SignDigest(signer, signingHash);
+ parcCryptoHash_Release(&signingHash);
+ }
+
+ // Now do the verification stage
+ PARCCryptoHash *verifierHash = NULL;
+ {
+ PARCCryptoHasher *verifyHasher = parcVerifier_GetCryptoHasher(verifier, NULL, PARCCryptoHashType_CRC32C);
+ parcCryptoHasher_Init(verifyHasher);
+ parcCryptoHasher_UpdateBytes(verifyHasher, vectors[i].buffer, vectors[i].length);
+ verifierHash = parcCryptoHasher_Finalize(verifyHasher);
+ }
+
+ bool success = parcVerifier_VerifyDigestSignature(verifier, NULL, verifierHash, PARCCryptoSuite_NULL_CRC32C, sig);
+
+ assertTrue(success,
+ "Failed to verify signature, index %d expected 0x%08x\n",
+ i, vectors[i].crc32c);
+
+ parcSignature_Release(&sig);
+ parcCryptoHash_Release(&verifierHash);
+ }
+ parcSigner_Release(&signer);
+ parcVerifier_Release(&verifier);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxValidationCRC32C_DictionaryCryptoSuiteValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxTlvDictionary *dictionary = ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ data->keyname,
+ CCNxPayloadType_DATA,
+ NULL);
+ ccnxValidationCRC32C_Set(dictionary);
+ uint64_t cryptosuite = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ assertTrue(cryptosuite == PARCCryptoSuite_NULL_CRC32C, "Unexpected PARCCryptoSuite value in dictionary");
+
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxValidation_CRC32C);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/validation/test/test_ccnxValidation_EcSecp256K1.c b/libccnx-common/ccnx/common/validation/test/test_ccnxValidation_EcSecp256K1.c
new file mode 100755
index 00000000..8fe00f35
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/test/test_ccnxValidation_EcSecp256K1.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxValidation_EcSecp256K1.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+#include "testrig_validation.c"
+
+LONGBOW_TEST_RUNNER(ccnxValidation_EcSecp256K1)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxValidation_EcSecp256K1)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxValidation_EcSecp256K1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxValidationEcSecp256K1_Set);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxValidationEcSecp256K1_DictionaryCryptoSuiteValue);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxValidationEcSecp256K1_Set)
+{
+ // Do not run over V0 packets, no support
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testValidationSet_KeyId_KeyLocator(data, ccnxValidationEcSecp256K1_Set, ccnxValidationEcSecp256K1_Test, false, true);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxValidationEcSecp256K1_DictionaryCryptoSuiteValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxTlvDictionary *dictionary = ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ data->keyname,
+ CCNxPayloadType_DATA,
+ NULL);
+ ccnxValidationEcSecp256K1_Set(dictionary, data->keyid, NULL);
+ uint64_t cryptosuite = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ assertTrue(cryptosuite == PARCCryptoSuite_EC_SECP_256K1, "Unexpected PARCCryptoSuite value in dictionary");
+
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxValidation_EcSecp256K1);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/validation/test/test_ccnxValidation_HmacSha256.c b/libccnx-common/ccnx/common/validation/test/test_ccnxValidation_HmacSha256.c
new file mode 100755
index 00000000..4d095567
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/test/test_ccnxValidation_HmacSha256.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxValidation_HmacSha256.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <parc/algol/parc_Object.h>
+
+#include <LongBow/unit-test.h>
+#include "testrig_validation.c"
+
+LONGBOW_TEST_RUNNER(ccnxValidation_HmacSha256)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxValidation_HmacSha256)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxValidation_HmacSha256)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxValidationHmacSha256_Set);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxValidationHmacSha256_CreateSigner);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxValidationHmacSha256_DictionaryCryptoSuiteValue);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxValidationHmacSha256_Set)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testValidationSet_KeyId(data, ccnxValidationHmacSha256_Set, ccnxValidationHmacSha256_Test, true, true);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxValidationHmacSha256_CreateSigner)
+{
+ char secretKeyString[] = "0123456789ABCDEF0123456789ABCDEF";
+ PARCBuffer *secretKey = bufferFromString(strlen(secretKeyString), secretKeyString);
+
+ PARCSigner *signer = ccnxValidationHmacSha256_CreateSigner(secretKey);
+ assertNotNull(signer, "Got null signer");
+
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&secretKey);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxValidationHmacSha256_DictionaryCryptoSuiteValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxTlvDictionary *dictionary = ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ data->keyname,
+ CCNxPayloadType_DATA,
+ NULL);
+ ccnxValidationHmacSha256_Set(dictionary, data->keyid);
+ uint64_t cryptosuite = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ assertTrue(cryptosuite == PARCCryptoSuite_HMAC_SHA256, "Unexpected PARCCryptoSuite value in dictionary");
+
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxValidation_HmacSha256);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/validation/test/test_ccnxValidation_RsaSha256.c b/libccnx-common/ccnx/common/validation/test/test_ccnxValidation_RsaSha256.c
new file mode 100755
index 00000000..5119a262
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/test/test_ccnxValidation_RsaSha256.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../ccnxValidation_RsaSha256.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+#include "testrig_validation.c"
+#include <ccnx/common/validation/ccnxValidation_HmacSha256.h>
+
+
+LONGBOW_TEST_RUNNER(ccnxValidation_RsaSha256)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnxValidation_RsaSha256)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnxValidation_RsaSha256)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxValidationRsaSha256_Set);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxValidationRsaSha256_DictionaryCryptoSuiteValue);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxValidationRsaSha256_Set)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testValidationSet_KeyId_KeyLocator(data, ccnxValidationRsaSha256_Set, ccnxValidationRsaSha256_Test, true, true);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxValidationRsaSha256_DictionaryCryptoSuiteValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxTlvDictionary *dictionary = ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ data->keyname,
+ CCNxPayloadType_DATA,
+ NULL);
+ ccnxValidationRsaSha256_Set(dictionary, data->keyid, NULL);
+
+ uint64_t cryptosuite = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE);
+ assertTrue(cryptosuite == PARCCryptoSuite_RSA_SHA256, "Unexpected PARCCryptoSuite value in dictionary");
+
+ ccnxTlvDictionary_Release(&dictionary);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxValidation_RsaSha256);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-common/ccnx/common/validation/test/testrig_validation.c b/libccnx-common/ccnx/common/validation/test/testrig_validation.c
new file mode 100755
index 00000000..185be143
--- /dev/null
+++ b/libccnx-common/ccnx/common/validation/test/testrig_validation.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Common routines to test validators
+ *
+ */
+
+#include <ccnx/common/ccnx_KeyLocator.h>
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+
+#include <ccnx/common/ccnx_ContentObject.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+typedef struct test_data {
+ PARCBuffer *keyid;
+ PARCBuffer *key;
+ PARCBuffer *cert;
+ CCNxName *keyname;
+
+ CCNxKeyLocator *locatorByKey;
+ CCNxKeyLocator *locatorByName;
+} TestData;
+
+PARCBuffer *
+bufferFromString(size_t length, const char string[length])
+{
+ return parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(length), length, (const uint8_t *) string));
+}
+
+TestData *
+testData_Create(void)
+{
+ char keyidString[] = "the keyid";
+ char keyString[] = "Memory, all alone in the moonlight";
+ char certString[] = "The quick brown fox";
+
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->keyid = bufferFromString(sizeof(keyidString), keyidString);
+ data->key = bufferFromString(sizeof(keyString), keyString);
+ data->cert = bufferFromString(sizeof(certString), certString);
+ data->keyname = ccnxName_CreateFromCString("lci:/lazy/dog");
+
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, data->key);
+
+ data->locatorByKey = ccnxKeyLocator_CreateFromKey(key);
+ parcKey_Release(&key);
+ parcKeyId_Release(&keyid);
+
+ CCNxLink *link = ccnxLink_Create(data->keyname, NULL, NULL);
+ data->locatorByName = ccnxKeyLocator_CreateFromKeyLink(link);
+ ccnxLink_Release(&link);
+
+ return data;
+}
+
+void
+testData_Release(TestData **dataPtr)
+{
+ TestData *data = *dataPtr;
+
+ ccnxKeyLocator_Release(&data->locatorByKey);
+ ccnxKeyLocator_Release(&data->locatorByName);
+ ccnxName_Release(&data->keyname);
+ parcBuffer_Release(&data->cert);
+ parcBuffer_Release(&data->key);
+ parcBuffer_Release(&data->keyid);
+
+ parcMemory_Deallocate((void **) &data);
+ *dataPtr = NULL;
+}
+
+TestData *
+commonSetup(void)
+{
+ TestData *data = testData_Create();
+ return data;
+}
+
+int
+commonTeardown(TestData *data)
+{
+ testData_Release(&data);
+ return 0;
+}
+
+// === V1
+
+void
+testValidationSetV1_NoParam(TestData *data, bool (*set)(CCNxTlvDictionary *message), bool (*test)(const CCNxTlvDictionary *message))
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/parc/validation/test");
+ CCNxTlvDictionary *packetV1 = ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name,
+ CCNxPayloadType_DATA,
+ NULL);
+ bool success = set(packetV1);
+ assertTrue(success, "Failed to set on V1");
+
+ bool testResult = test(packetV1);
+ assertTrue(testResult, "Test function failed on V1 packet");
+
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&packetV1);
+}
+
+void
+testValidationSetV1_KeyId_Null(TestData *data, bool (*set)(CCNxTlvDictionary *message, const PARCBuffer *keyid), bool (*test)(const CCNxTlvDictionary *message))
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/parc/validation/test");
+ CCNxTlvDictionary *packetV1 = ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name,
+ CCNxPayloadType_DATA,
+ NULL);
+ bool success = set(packetV1, NULL);
+ assertTrue(success, "Failed to set on V1");
+
+ bool testResult = test(packetV1);
+ assertTrue(testResult, "Test function failed on V1 packet");
+
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&packetV1);
+}
+
+void
+testValidationSetV1_KeyId_KeyId(TestData *data, bool (*set)(CCNxTlvDictionary *message, const PARCBuffer *keyid), bool (*test)(const CCNxTlvDictionary *message))
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/parc/validation/test");
+ CCNxTlvDictionary *packetV1 = ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name,
+ CCNxPayloadType_DATA,
+ NULL);
+ bool success = set(packetV1, data->keyid);
+ assertTrue(success, "Failed to set on V1");
+
+ bool testResult = test(packetV1);
+ assertTrue(testResult, "Test function failed on V1 packet");
+
+ PARCBuffer *testKeyId = ccnxValidationFacadeV1_GetKeyId(packetV1);
+ assertTrue(parcBuffer_Equals(testKeyId, data->keyid), "keyid not equal");
+
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&packetV1);
+}
+
+void
+testValidationSetV1_KeyId_KeyLocator_Null_Null(TestData *data,
+ bool (*set)(CCNxTlvDictionary *message, const PARCBuffer *keyid,
+ const CCNxKeyLocator *keyLocator),
+ bool (*test)(const CCNxTlvDictionary *message))
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/parc/validation/test");
+ CCNxTlvDictionary *packetV1 = ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name,
+ CCNxPayloadType_DATA,
+ NULL);
+ bool success = set(packetV1, NULL, NULL);
+ assertTrue(success, "Failed to set on V1");
+
+ bool testResult = test(packetV1);
+ assertTrue(testResult, "Test function failed on V1 packet");
+
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&packetV1);
+}
+
+void
+testValidationSetV1_KeyId_KeyLocator_KeyId_Null(TestData *data,
+ bool (*set)(CCNxTlvDictionary *message, const PARCBuffer *keyid,
+ const CCNxKeyLocator *keyLocator),
+ bool (*test)(const CCNxTlvDictionary *message))
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/parc/validation/test");
+ CCNxTlvDictionary *packetV1 = ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name,
+ CCNxPayloadType_DATA,
+ NULL);
+ bool success = set(packetV1, data->keyid, NULL);
+ assertTrue(success, "Failed to set on V1");
+
+ bool testResult = test(packetV1);
+ assertTrue(testResult, "Test function failed on V1 packet");
+
+ PARCBuffer *testKeyId = ccnxValidationFacadeV1_GetKeyId(packetV1);
+ assertTrue(parcBuffer_Equals(testKeyId, data->keyid), "keyid not equal");
+
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&packetV1);
+}
+
+void
+testValidationSetV1_KeyId_KeyLocator_KeyId_Key(TestData *data,
+ bool (*set)(CCNxTlvDictionary *message, const PARCBuffer *keyid,
+ const CCNxKeyLocator *keyLocator),
+ bool (*test)(const CCNxTlvDictionary *message))
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/parc/validation/test");
+ CCNxTlvDictionary *packetV1 = ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name,
+ CCNxPayloadType_DATA,
+ NULL);
+ bool success = set(packetV1, data->keyid, data->locatorByKey);
+ assertTrue(success, "Failed to set on V1");
+
+ bool testResult = test(packetV1);
+ assertTrue(testResult, "Test function failed on V1 packet");
+
+ PARCBuffer *testKeyId = ccnxValidationFacadeV1_GetKeyId(packetV1);
+ assertTrue(parcBuffer_Equals(testKeyId, data->keyid), "keyid not equal");
+
+ PARCBuffer *testKey = ccnxValidationFacadeV1_GetPublicKey(packetV1);
+ assertTrue(parcBuffer_Equals(testKey, data->key), "keys not equal");
+
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&packetV1);
+}
+
+void
+testValidationSetV1_KeyId_KeyLocator_KeyId_KeyName(TestData *data,
+ bool (*set)(CCNxTlvDictionary *message, const PARCBuffer *keyid,
+ const CCNxKeyLocator *keyLocator),
+ bool (*test)(const CCNxTlvDictionary *message))
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/parc/validation/test");
+ CCNxTlvDictionary *packetV1 = ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation,
+ name,
+ CCNxPayloadType_DATA,
+ NULL);
+ bool success = set(packetV1, data->keyid, data->locatorByName);
+ assertTrue(success, "Failed to set on V1");
+
+ bool testResult = test(packetV1);
+ assertTrue(testResult, "Test function failed on V1 packet");
+
+ PARCBuffer *testKeyId = ccnxValidationFacadeV1_GetKeyId(packetV1);
+ assertTrue(parcBuffer_Equals(testKeyId, data->keyid), "keyid not equal");
+
+ // XXX: TODO: GetKeyName() returns a Link, so it should be GetLink().
+ // It also creates a new object (the CCNxLink), so... needs thinking about.
+ // See BugzId: 3322
+
+ CCNxLink *testLink = ccnxValidationFacadeV1_GetKeyName(packetV1);
+ assertTrue(ccnxName_Equals(ccnxLink_GetName(testLink), data->keyname), "Keynames not equal");
+ ccnxLink_Release(&testLink);
+
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&packetV1);
+}
+
+// === General test for public key algs
+
+void
+testValidationSet_KeyId_KeyLocator(TestData *data, bool (*set)(CCNxTlvDictionary *message, const PARCBuffer *keyid, const CCNxKeyLocator *keyLocator), bool (*test)(const CCNxTlvDictionary *message), bool v0ok, bool v1ok)
+{
+ if (v1ok) {
+ testValidationSetV1_KeyId_KeyLocator_Null_Null(data, set, test);
+ testValidationSetV1_KeyId_KeyLocator_KeyId_Null(data, set, test);
+ testValidationSetV1_KeyId_KeyLocator_KeyId_Key(data, set, test);
+ testValidationSetV1_KeyId_KeyLocator_KeyId_KeyName(data, set, test);
+ }
+}
+
+void
+testValidationSet_KeyId(TestData *data, bool (*set)(CCNxTlvDictionary *message, const PARCBuffer *keyid), bool (*test)(const CCNxTlvDictionary *message), bool v0ok, bool v1ok)
+{
+ if (v1ok) {
+ testValidationSetV1_KeyId_Null(data, set, test);
+ testValidationSetV1_KeyId_KeyId(data, set, test);
+ }
+}
+
+void
+testValidationSet_NoParam(TestData *data, bool (*set)(CCNxTlvDictionary *message), bool (*test)(const CCNxTlvDictionary *message), bool v0ok, bool v1ok)
+{
+ if (v1ok) {
+ testValidationSetV1_NoParam(data, set, test);
+ testValidationSetV1_NoParam(data, set, test);
+ }
+}
diff --git a/libccnx-common/cmake/Modules/FindLibEvent.cmake b/libccnx-common/cmake/Modules/FindLibEvent.cmake
new file mode 100644
index 00000000..2d1ca4fe
--- /dev/null
+++ b/libccnx-common/cmake/Modules/FindLibEvent.cmake
@@ -0,0 +1,47 @@
+########################################
+#
+# Find the LibEvent libraries and includes
+# This module sets:
+# LIBEVENT_FOUND: True if LibEvent was found
+# LIBEVENT_LIBRARY: The LibEvent library
+# LIBEVENT_LIBRARIES: The LibEvent library and dependencies
+# LIBEVENT_INCLUDE_DIR: The LibEvent include dir
+#
+# This module will look for the libraries in various locations
+# See the LIBEVENT_SEARCH_PATH_LIST for a full list.
+#
+# The caller can hint at locations using the following variables:
+#
+# LIBEVENT_HOME (passed as -D to cmake)
+# CCNX_DEPENDENCIES (in environment)
+# LIBEVENT_HOME (in environment)
+# CCNX_HOME (in environment)
+#
+
+set(LIBEVENT_SEARCH_PATH_LIST
+ ${LIBEVENT_HOME}
+ $ENV{CCNX_DEPENDENCIES}
+ $ENV{LIBEVENT_HOME}
+ $ENV{CCNX_HOME}
+ /usr/local/ccnx
+ /usr/local/ccn
+ /usr/local
+ /opt
+ /usr
+ )
+
+find_path(LIBEVENT_INCLUDE_DIR event2/event.h
+ HINTS ${LIBEVENT_SEARCH_PATH_LIST}
+ PATH_SUFFIXES include
+ DOC "Find the LibEvent includes" )
+
+find_library(LIBEVENT_LIBRARY NAMES event
+ HINTS ${LIBEVENT_SEARCH_PATH_LIST}
+ PATH_SUFFIXES lib
+ DOC "Find the LibEvent libraries" )
+
+set(LIBEVENT_LIBRARIES ${LIBEVENT_LIBRARY})
+set(LIBEVENT_INCLUDE_DIRS ${LIBEVENT_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LibEvent DEFAULT_MSG LIBEVENT_LIBRARY LIBEVENT_INCLUDE_DIR)
diff --git a/libccnx-common/cmake/Modules/FindLibparc.cmake b/libccnx-common/cmake/Modules/FindLibparc.cmake
new file mode 100644
index 00000000..02835161
--- /dev/null
+++ b/libccnx-common/cmake/Modules/FindLibparc.cmake
@@ -0,0 +1,39 @@
+########################################
+#
+# Find the Libparc libraries and includes
+# This module sets:
+# LIBPARC_FOUND: True if Libparc was found
+# LIBPARC_LIBRARY: The Libparc library
+# LIBPARC_LIBRARIES: The Libparc library and dependencies
+# LIBPARC_INCLUDE_DIR: The Libparc include dir
+#
+
+set(LIBPARC_SEARCH_PATH_LIST
+ ${LIBPARC_HOME}
+ $ENV{LIBPARC_HOME}
+ $ENV{CCNX_HOME}
+ $ENV{PARC_HOME}
+ $ENV{FOUNDATION_HOME}
+ /usr/local/parc
+ /usr/local/ccnx
+ /usr/local/ccn
+ /usr/local
+ /opt
+ /usr
+ )
+
+find_path(LIBPARC_INCLUDE_DIR parc/libparc_About.h
+ HINTS ${LIBPARC_SEARCH_PATH_LIST}
+ PATH_SUFFIXES include
+ DOC "Find the Libparc includes" )
+
+find_library(LIBPARC_LIBRARY NAMES parc
+ HINTS ${LIBPARC_SEARCH_PATH_LIST}
+ PATH_SUFFIXES lib
+ DOC "Find the Libparc libraries" )
+
+set(LIBPARC_LIBRARIES ${LIBPARC_LIBRARY})
+set(LIBPARC_INCLUDE_DIRS ${LIBPARC_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Libparc DEFAULT_MSG LIBPARC_LIBRARY LIBPARC_INCLUDE_DIR)
diff --git a/libccnx-common/cmake/Modules/FindLongBow.cmake b/libccnx-common/cmake/Modules/FindLongBow.cmake
new file mode 100644
index 00000000..e35888eb
--- /dev/null
+++ b/libccnx-common/cmake/Modules/FindLongBow.cmake
@@ -0,0 +1,44 @@
+########################################
+#
+# Find the LongBow libraries and includes
+# This module sets:
+# LONGBOW_FOUND: True if LongBow was found
+# LONGBOW_LIBRARY: The LongBow library
+# LONGBOW_LIBRARIES: The LongBow library and dependencies
+# LONGBOW_INCLUDE_DIR: The LongBow include dir
+#
+
+set(LONGBOW_SEARCH_PATH_LIST
+ ${LONGBOW_HOME}
+ $ENV{LONGBOW_HOME}
+ $ENV{CCNX_HOME}
+ $ENV{PARC_HOME}
+ $ENV{FOUNDATION_HOME}
+ /usr/local/parc
+ /usr/local/ccnx
+ /usr/local/ccn
+ /usr/local
+ /opt
+ /usr
+ )
+
+find_path(LONGBOW_INCLUDE_DIR LongBow/longBow_About.h
+ HINTS ${LONGBOW_SEARCH_PATH_LIST}
+ PATH_SUFFIXES include
+ DOC "Find the LongBow includes" )
+
+find_library(LONGBOW_LIBRARY NAMES longbow
+ HINTS ${LONGBOW_SEARCH_PATH_LIST}
+ PATH_SUFFIXES lib
+ DOC "Find the LongBow libraries" )
+
+find_library(LONGBOW_REPORT_LIBRARY NAMES longbow-textplain longbow-ansiterm
+ HINTS ${LONGBOW_SEARCH_PATH_LIST}
+ PATH_SUFFIXES lib
+ DOC "Find the LongBow report libraries" )
+
+set(LONGBOW_LIBRARIES ${LONGBOW_LIBRARY} ${LONGBOW_REPORT_LIBRARY})
+set(LONGBOW_INCLUDE_DIRS ${LONGBOW_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LongBow DEFAULT_MSG LONGBOW_LIBRARY LONGBOW_INCLUDE_DIR)
diff --git a/libccnx-common/cmake/Modules/FindUncrustify.cmake b/libccnx-common/cmake/Modules/FindUncrustify.cmake
new file mode 100644
index 00000000..e53f65fe
--- /dev/null
+++ b/libccnx-common/cmake/Modules/FindUncrustify.cmake
@@ -0,0 +1,8 @@
+# Find uncrustify program
+#
+find_program( UNCRUSTIFY_BIN uncrustify
+ PATHS
+ $ENV{UNCRUSTIFY_HOME}
+ )
+
+message( "-- UNCRUSTIFY found in ${UNCRUSTIFY_BIN}" )
diff --git a/libccnx-common/cmake/Modules/detectCacheSize.cmake b/libccnx-common/cmake/Modules/detectCacheSize.cmake
new file mode 100644
index 00000000..469d2627
--- /dev/null
+++ b/libccnx-common/cmake/Modules/detectCacheSize.cmake
@@ -0,0 +1,21 @@
+# Detect the cache size
+#
+# XXX: TODO: This is a bug when cross compiling. We are detecting the local
+# Cache Line size and not the target cache line size. We should provide some
+# way to define this
+
+set(LEVEL1_DCACHE_LINESIZE 32)
+
+if( APPLE )
+ execute_process(COMMAND sysctl -n hw.cachelinesize
+ OUTPUT_VARIABLE LEVEL1_DCACHE_LINESIZE
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+endif( APPLE )
+
+if( ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" )
+ execute_process(COMMAND getconf LEVEL1_DCACHE_LINESIZE
+ OUTPUT_VARIABLE LEVEL1_DCACHE_LINESIZE
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+endif()
+
+message("-- Cache line size: ${LEVEL1_DCACHE_LINESIZE}")
diff --git a/libccnx-common/cmake/Modules/version.cmake b/libccnx-common/cmake/Modules/version.cmake
new file mode 100644
index 00000000..74831674
--- /dev/null
+++ b/libccnx-common/cmake/Modules/version.cmake
@@ -0,0 +1,15 @@
+#
+# Get a version to pass on the command line
+#
+execute_process(COMMAND ${PROJECT_SOURCE_DIR}/cmake/get_version.sh ${PROJECT_SOURCE_DIR}
+ OUTPUT_VARIABLE RELEASE_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+execute_process(COMMAND date -u +%Y-%m-%dT%H:%M:%SZ
+ OUTPUT_VARIABLE ISO_DATE
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+MESSAGE( STATUS "Configuring version ${RELEASE_VERSION}" )
+
+add_definitions("-DRELEASE_VERSION=\"${RELEASE_VERSION}\"")
+
diff --git a/libccnx-common/cmake/get_version.sh b/libccnx-common/cmake/get_version.sh
new file mode 100755
index 00000000..34c6ddb2
--- /dev/null
+++ b/libccnx-common/cmake/get_version.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+DATE_VERSION=`date "+%Y%m%d"`
+
+if [ ! -d $1 ]; then
+ echo 0.$DATE_VERSION
+ exit
+fi
+
+if [ -f $1/BASE_VERSION ]; then
+ BASE_VERSION=`cat $1/BASE_VERSION`.
+fi
+
+GIT=`which git`
+
+if test -x $GIT -a -f $1/.git/config; then
+ GIT_VERSION=.`git -C $1 rev-parse HEAD | cut -c 1-8`
+fi
+
+echo $BASE_VERSION$DATE_VERSION$GIT_VERSION
diff --git a/libccnx-common/documentation/.gitignore b/libccnx-common/documentation/.gitignore
new file mode 100644
index 00000000..bb5d033a
--- /dev/null
+++ b/libccnx-common/documentation/.gitignore
@@ -0,0 +1,9 @@
+*.doctags
+Jekyll
+libccnx-documentation
+libccnx_api_control-documentation
+libccnx_api_keyvalue-documentation
+libccnx_api_mqueue-documentation
+libccnx_api_notify-documentation
+libccnx_api_portal-documentation
+librta-documentation
diff --git a/libccnx-common/documentation/CMakeLists.txt b/libccnx-common/documentation/CMakeLists.txt
new file mode 100644
index 00000000..9b934e03
--- /dev/null
+++ b/libccnx-common/documentation/CMakeLists.txt
@@ -0,0 +1,49 @@
+find_package(Doxygen)
+
+if(DOXYGEN_FOUND)
+ set(PARC_REMOTE http://githubenterprise.parc.com/CCNX/Libccnx-common)
+ set(GITHUB_REMOTE http://github.com/PARC/Libccnx-common)
+ configure_file(libccnx-stage1.doxygen.in config.doxygen @ONLY)
+ configure_file(libccnx-stage2.doxygen.in config2.doxygen @ONLY)
+
+ install(DIRECTORY images/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/images)
+ install(DIRECTORY doxygen-extras/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/doxygen-extras)
+ install(DIRECTORY examples/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/examples)
+ install(FILES DoxygenLayout.xml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+
+ set(HTML_PATH ${CMAKE_CURRENT_BINARY_DIR}/generated-documentation/html)
+
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/documentation.tar
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/config.doxygen
+ COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/config2.doxygen
+ COMMAND tar cf documentation.tar -C ${HTML_PATH} .
+ COMMENT "The file documentation.tar contains the HTML website suitable to update/replace the gh-pages branch of this repository." VERBATIM )
+
+ add_custom_target(documentation
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/documentation.tar
+ WORKING_DIRECTORY ${HTML_PATH})
+
+ add_custom_command(OUTPUT ${HTML_PATH}/.git/config
+ DEPENDS documentation
+ WORKING_DIRECTORY ${HTML_PATH}
+ COMMAND git init .
+ COMMAND git checkout -B gh-pages
+ COMMAND git add .
+ COMMAND git commit -am 'Override all previous versions'
+ COMMAND git remote add parc ${PARC_REMOTE}
+ COMMAND git remote add github ${GITHUB_REMOTE})
+
+ add_custom_target(documentation-install-parc
+ COMMENT "Push to ${PARC_REMOTE} gh-pages"
+ DEPENDS ${HTML_PATH}/.git/config
+ WORKING_DIRECTORY ${HTML_PATH}
+ COMMAND git push parc gh-pages -f)
+
+ add_custom_target(documentation-install-github
+ COMMENT "Push to ${GITHUB_REMOTE} gh-pages"
+ DEPENDS ${HTML_PATH}/.git/config
+ WORKING_DIRECTORY ${HTML_PATH}
+ COMMAND git push github gh-pages -f)
+
+endif(DOXYGEN_FOUND)
diff --git a/libccnx-common/documentation/DoxygenLayout.xml b/libccnx-common/documentation/DoxygenLayout.xml
new file mode 100644
index 00000000..759a9cd4
--- /dev/null
+++ b/libccnx-common/documentation/DoxygenLayout.xml
@@ -0,0 +1,196 @@
+<doxygenlayout version="1.0">
+ <!-- Generated by doxygen 1.8.9.1 -->
+ <!-- Navigation index tabs for HTML output -->
+ <navindex>
+ <tab type="mainpage" visible="yes" title="Overview"/>
+ <tab type="pages" visible="yes" title="" intro=""/>
+ <tab type="modules" visible="yes" title="" intro=""/>
+ <tab type="namespaces" visible="yes" title="">
+ <tab type="namespacelist" visible="yes" title="" intro=""/>
+ <tab type="namespacemembers" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="classes" visible="yes" title="Public Types">
+ <tab type="classlist" visible="yes" title="Type List" intro=""/>
+ <tab type="classindex" visible="$ALPHABETICAL_INDEX" title="Type Index"/>
+ <tab type="hierarchy" visible="yes" title="" intro=""/>
+ <tab type="classmembers" visible="no" title="" intro=""/>
+ </tab>
+ <tab type="globals" visible="yes" title="Global Entities" intro=""/>
+
+ <tab type="files" visible="no" title="">
+ <tab type="filelist" visible="yes" title="" intro=""/>
+ <tab type="globals" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="examples" visible="yes" title="" intro=""/>
+ </navindex>
+
+ <!-- Layout definition for a class page -->
+ <class>
+ <briefdescription visible="yes"/>
+ <detaileddescription title=""/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <inheritancegraph visible="$CLASS_GRAPH"/>
+ <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+ <memberdecl>
+ <nestedclasses visible="yes" title=""/>
+ <publictypes title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <publicslots title=""/>
+ <signals title=""/>
+ <publicmethods title=""/>
+ <publicstaticmethods title=""/>
+ <publicattributes title=""/>
+ <publicstaticattributes title=""/>
+ <protectedtypes title=""/>
+ <protectedslots title=""/>
+ <protectedmethods title=""/>
+ <protectedstaticmethods title=""/>
+ <protectedattributes title=""/>
+ <protectedstaticattributes title=""/>
+ <packagetypes title=""/>
+ <packagemethods title=""/>
+ <packagestaticmethods title=""/>
+ <packageattributes title=""/>
+ <packagestaticattributes title=""/>
+ <properties title=""/>
+ <events title=""/>
+ <privatetypes title=""/>
+ <privateslots title=""/>
+ <privatemethods title=""/>
+ <privatestaticmethods title=""/>
+ <privateattributes title=""/>
+ <privatestaticattributes title=""/>
+ <friends title=""/>
+ <related title="" subtitle=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <constructors title=""/>
+ <functions title=""/>
+ <related title=""/>
+ <variables title=""/>
+ <properties title=""/>
+ <events title=""/>
+ </memberdef>
+ <allmemberslink visible="yes"/>
+ <usedfiles visible="$SHOW_USED_FILES"/>
+ <authorsection visible="yes"/>
+ </class>
+
+ <!-- Layout definition for a namespace page -->
+ <namespace>
+ <briefdescription visible="yes"/>
+ <detaileddescription title=""/>
+ <memberdecl>
+ <nestednamespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </namespace>
+
+ <!-- Layout definition for a file page -->
+ <file>
+ <briefdescription visible="yes"/>
+ <detaileddescription title=""/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <includegraph visible="$INCLUDE_GRAPH"/>
+ <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+ <sourcelink visible="yes"/>
+ <memberdecl>
+ <classes visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection/>
+ </file>
+
+ <!-- Layout definition for a group page -->
+ <group>
+ <briefdescription visible="yes"/>
+ <detaileddescription title=""/>
+ <groupgraph visible="$GROUP_GRAPHS"/>
+ <memberdecl>
+ <nestedgroups visible="yes" title=""/>
+ <dirs visible="yes" title=""/>
+ <files visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <pagedocs/>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </group>
+
+ <!-- Layout definition for a directory page -->
+ <directory>
+ <briefdescription visible="yes"/>
+ <detaileddescription title=""/>
+ <directorygraph visible="yes"/>
+ <memberdecl>
+ <dirs visible="yes"/>
+ <files visible="yes"/>
+ </memberdecl>
+ </directory>
+</doxygenlayout>
diff --git a/libccnx-common/documentation/Makefile.am b/libccnx-common/documentation/Makefile.am
new file mode 100644
index 00000000..9c9ea0e5
--- /dev/null
+++ b/libccnx-common/documentation/Makefile.am
@@ -0,0 +1,89 @@
+#
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+include ../config.mk
+
+docs: doxygen
+
+doxygen: Makefile stage1 stage2
+
+stage1: stage1-message doxygen-libccnx-stage1 doxygen-libccnx_api_control-stage1 doxygen-libccnx_api_notify-stage1 doxygen-libccnx_api_portal-stage1 doxygen-librta-stage1
+stage2: stage2-message doxygen-libccnx-stage2 doxygen-libccnx_api_control-stage2 doxygen-libccnx_api_notify-stage2 doxygen-libccnx_api_portal-stage2 doxygen-librta-stage2
+
+# Stage 1
+
+stage1-message:
+ @echo
+ @echo !! Running doxygen to create *only* TAG files.
+ @echo
+
+doxygen-libccnx-stage1: libccnx-stage1.doxygen
+ ${DOXYGEN_BIN} -s libccnx-stage1.doxygen >& doxygen-libccnx-stage1.log
+
+doxygen-libccnx_api_control-stage1: libccnx_api_control-stage1.doxygen
+ ${DOXYGEN_BIN} -s libccnx_api_control-stage1.doxygen >& doxygen-libccnx_api_control-stage1.log
+
+doxygen-libccnx_api_notify-stage1: libccnx_api_notify-stage1.doxygen
+ ${DOXYGEN_BIN} -s libccnx_api_notify-stage1.doxygen >& doxygen-libccnx_api_notify-stage1.log
+
+doxygen-libccnx_api_portal-stage1: libccnx_api_portal-stage1.doxygen
+ ${DOXYGEN_BIN} -s libccnx_api_portal-stage1.doxygen >& doxygen-libccnx_api_portal-stage1.log
+
+doxygen-librta-stage1: librta-stage1.doxygen
+ ${DOXYGEN_BIN} -s librta-stage1.doxygen >& doxygen-librta-stage1.log
+
+# Stage 2
+
+stage2-message:
+ @echo
+ @echo !! Now running doxygen to create documentation, referencing previously generated TAG files.
+ @echo
+
+doxygen-libccnx-stage2: libccnx-stage2.doxygen
+ ${DOXYGEN_BIN} -s libccnx-stage2.doxygen >& doxygen-libccnx-stage2.log
+ ${LONGBOW_DOXYGEN_BIN_REPORT} --doxygenlog doxygen-libccnx-stage2.log
+
+doxygen-libccnx_api_control-stage2: libccnx_api_control-stage2.doxygen
+ ${DOXYGEN_BIN} -s libccnx_api_control-stage2.doxygen >& doxygen-libccnx_api_control-stage2.log
+ ${LONGBOW_DOXYGEN_BIN_REPORT} --doxygenlog doxygen-libccnx_api_control-stage2.log
+
+doxygen-libccnx_api_notify-stage2: libccnx_api_notify-stage2.doxygen
+ ${DOXYGEN_BIN} -s libccnx_api_notify-stage2.doxygen >& doxygen-libccnx_api_notify-stage2.log
+ ${LONGBOW_DOXYGEN_BIN_REPORT} --doxygenlog doxygen-libccnx_api_notify-stage2.log
+
+doxygen-libccnx_api_portal-stage2: libccnx_api_portal-stage2.doxygen
+ ${DOXYGEN_BIN} -s libccnx_api_portal-stage2.doxygen >& doxygen-libccnx_api_portal-stage2.log
+ ${LONGBOW_DOXYGEN_BIN_REPORT} --doxygenlog doxygen-libccnx_api_portal-stage2.log
+
+doxygen-librta-stage2: librta-stage2.doxygen
+ ${DOXYGEN_BIN} -s librta-stage2.doxygen >& doxygen-librta-stage2.log
+ ${LONGBOW_DOXYGEN_BIN_REPORT} --doxygenlog doxygen-librta-stage2.log
+
+website: doxygen
+ $(MAKE) -C Jekyll
+
+# The Doxygen output directory removed here is set in libparc.conf
+clobber: clean
+ ${RM} -r libccnx-documentation
+ ${RM} -r libccnx_api_control-documentation
+ ${RM} -r libccnx_api_keyvalue-documentation
+ ${RM} -r libccnx_api_mqueue-documentation
+ ${RM} -r libccnx_api_notify-documentation
+ ${RM} -r libccnx_api_portal-documentation
+ ${RM} -r librta-documentation
+
+CLEANFILES=doxygen.log doxygen-libccnx.log doxygen-libccnx_api_control.log \
+ doxygen-libccnx_api_keyvalue.log doxygen-libccnx_api_mqueue.log \
+ doxygen-libccnx_api_notify.log doxygen-libccnx_api_notify.log \
+ doxygen-libccnx_api_portal.log doxygen-librta.log *.doctags
diff --git a/libccnx-common/documentation/Makefile.notautomake b/libccnx-common/documentation/Makefile.notautomake
new file mode 100644
index 00000000..48080b75
--- /dev/null
+++ b/libccnx-common/documentation/Makefile.notautomake
@@ -0,0 +1,76 @@
+DOXYGEN=/Applications/Doxygen.app/Contents/Resources/doxygen
+INSTALLDIR=.
+
+# This needs to be the same filename that is in gh-pages branch, ./Makefile
+GHPAGES=/tmp/Libccnx-gh-pages.tgz
+
+all: doc
+
+score: all
+ (cd Jekyll/Libccnx/libccnx/latex ; make) | grep "Output.*pages" | tail -1 > libccnx.score
+ (echo Jekyll/Libccnx/libccnx/*.html | wc -w) >> libccnx.score
+ (cd Jekyll/Libccnx/libccnx_api_control-api/latex ; make) | grep "Output.*pages" | tail -1 > libccnx_api_control-api.score
+ (echo Jekyll/Libccnx/libccnx_api_control-api/*.html | wc -w) >> libccnx_api_control-api.score
+ (cd Jekyll/Libccnx/libccnx_api_notify-api/latex ; make) | grep "Output.*pages" | tail -1 > libccnx_api_notify-api.score
+ (echo Jekyll/Libccnx/libccnx_api_notify-api/*.html | wc -w ) >> libccnx_api_notify-api.score
+ (cd Jekyll/Libccnx/libccnx_api_portal/latex ; make) | grep "Output.*pages" | tail -1 > libccnx_api_portal.score
+ (echo Jekyll/Libccnx/libccnx_api_portal/*.html | wc -w) >> libccnx_api_portal.score
+ (cd Jekyll/Libccnx/librta/latex ; make) | grep "Output.*pages" | tail -1 > librta.score
+ (echo Jekyll/Libccnx/librta/*.html | wc -w) >> librta.score
+
+clean:
+ make -C Jekyll clean
+ rm -rf Jekyll/Libccnx/libccnx_api_control-api/
+ rm -rf Jekyll/Libccnx/libccnx_api_notify-api/
+ rm -rf Jekyll/Libccnx/libccnx_api_socket-api/
+ rm -rf Jekyll/Libccnx/libccnx_api_keyvalue-api/
+ rm -rf Jekyll/Libccnx/libccnx_api_mqueue-api/
+ rm -rf Jekyll/Libccnx/libccnx/
+ rm -rf Jekyll/Libccnx/librta/
+ ${RM} libccnx_api_mqueue.log libccnx_api_keyvalue.log libccnx_api_control.log libccnx_api_notify.log libccnx_api_socket.log libccnx.log librta.log *.score
+ ${RM} *.doctags
+
+help:
+ @echo "make doc Make the documentation"
+ @echo "make install Make a tar file containing the documentation suitable for a gh-page site."
+ @echo "make jekyll Make the Jekyll website (implicit when making 'doc')"
+ @echo "make all The same as make doc"
+
+doc: site libccnx libccnx_api_control libccnx_api_notify librta libccnx_api_mqueue libccnx_api_keyvalue libccnx_api_portal
+
+libccnx_api_mqueue:
+ ${DOXYGEN} doxygen-libccnx_api_mqueue.conf >& libccnx_api_mqueue.log
+
+libccnx_api_keyvalue:
+ ${DOXYGEN} doxygen-libccnx_api_keyvalue.conf >& libccnx_api_keyvalue.log
+
+libccnx_api_portal:
+ ${DOXYGEN} doxygen-libccnx_api_portal.conf >& libccnx_api_portal.log
+
+libccnx_api_control:
+ ${DOXYGEN} doxygen-libccnx_api_control.conf >& libccnx_api_control.log
+
+libccnx_api_notify:
+ ${DOXYGEN} doxygen-libccnx_api_notify.conf >& libccnx_api_notify.log
+
+libccnx_api_socket:
+ ${DOXYGEN} doxygen-libccnx_api_socket.conf >& libccnx_api_socket.log
+
+libccnx:
+ ${DOXYGEN} doxygen-libccnx.conf >& libccnx.log
+
+librta:
+ ${DOXYGEN} doxygen-librta.conf >& librta.log
+
+install: doc
+ make -C Jekyll clean build
+ (cd Jekyll/Libccnx/_site; tar czf ${GHPAGES} . )
+ @echo Now git checkout gh-pages and type make install
+
+site:
+ $(MAKE) -C Jekyll
+
+serve:
+ $(MAKE) -C Jekyll serve
+
+clobber: clean
diff --git a/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css b/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css
new file mode 100644
index 00000000..c4cadf15
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css
@@ -0,0 +1,470 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+.btn-default,
+.btn-primary,
+.btn-success,
+.btn-info,
+.btn-warning,
+.btn-danger {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+}
+.btn-default:active,
+.btn-primary:active,
+.btn-success:active,
+.btn-info:active,
+.btn-warning:active,
+.btn-danger:active,
+.btn-default.active,
+.btn-primary.active,
+.btn-success.active,
+.btn-info.active,
+.btn-warning.active,
+.btn-danger.active {
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn-default .badge,
+.btn-primary .badge,
+.btn-success .badge,
+.btn-info .badge,
+.btn-warning .badge,
+.btn-danger .badge {
+ text-shadow: none;
+}
+.btn:active,
+.btn.active {
+ background-image: none;
+}
+.btn-default {
+ text-shadow: 0 1px 0 #fff;
+ background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+ background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
+ background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #dbdbdb;
+ border-color: #ccc;
+}
+.btn-default:hover,
+.btn-default:focus {
+ background-color: #e0e0e0;
+ background-position: 0 -15px;
+}
+.btn-default:active,
+.btn-default.active {
+ background-color: #e0e0e0;
+ border-color: #dbdbdb;
+}
+.btn-default:disabled,
+.btn-default[disabled] {
+ background-color: #e0e0e0;
+ background-image: none;
+}
+.btn-primary {
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #245580;
+}
+.btn-primary:hover,
+.btn-primary:focus {
+ background-color: #265a88;
+ background-position: 0 -15px;
+}
+.btn-primary:active,
+.btn-primary.active {
+ background-color: #265a88;
+ border-color: #245580;
+}
+.btn-primary:disabled,
+.btn-primary[disabled] {
+ background-color: #265a88;
+ background-image: none;
+}
+.btn-success {
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
+ background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #3e8f3e;
+}
+.btn-success:hover,
+.btn-success:focus {
+ background-color: #419641;
+ background-position: 0 -15px;
+}
+.btn-success:active,
+.btn-success.active {
+ background-color: #419641;
+ border-color: #3e8f3e;
+}
+.btn-success:disabled,
+.btn-success[disabled] {
+ background-color: #419641;
+ background-image: none;
+}
+.btn-info {
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+ background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #28a4c9;
+}
+.btn-info:hover,
+.btn-info:focus {
+ background-color: #2aabd2;
+ background-position: 0 -15px;
+}
+.btn-info:active,
+.btn-info.active {
+ background-color: #2aabd2;
+ border-color: #28a4c9;
+}
+.btn-info:disabled,
+.btn-info[disabled] {
+ background-color: #2aabd2;
+ background-image: none;
+}
+.btn-warning {
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+ background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #e38d13;
+}
+.btn-warning:hover,
+.btn-warning:focus {
+ background-color: #eb9316;
+ background-position: 0 -15px;
+}
+.btn-warning:active,
+.btn-warning.active {
+ background-color: #eb9316;
+ border-color: #e38d13;
+}
+.btn-warning:disabled,
+.btn-warning[disabled] {
+ background-color: #eb9316;
+ background-image: none;
+}
+.btn-danger {
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+ background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #b92c28;
+}
+.btn-danger:hover,
+.btn-danger:focus {
+ background-color: #c12e2a;
+ background-position: 0 -15px;
+}
+.btn-danger:active,
+.btn-danger.active {
+ background-color: #c12e2a;
+ border-color: #b92c28;
+}
+.btn-danger:disabled,
+.btn-danger[disabled] {
+ background-color: #c12e2a;
+ background-image: none;
+}
+.thumbnail,
+.img-thumbnail {
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+ background-color: #e8e8e8;
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+ background-repeat: repeat-x;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ background-color: #2e6da4;
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+ background-repeat: repeat-x;
+}
+.navbar-default {
+ background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+ background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
+ background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .active > a {
+ background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+ background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
+ background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
+ background-repeat: repeat-x;
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+}
+.navbar-brand,
+.navbar-nav > li > a {
+ text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
+}
+.navbar-inverse {
+ background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
+ background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
+ background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .active > a {
+ background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
+ background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
+ background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
+ background-repeat: repeat-x;
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+}
+.navbar-inverse .navbar-brand,
+.navbar-inverse .navbar-nav > li > a {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
+}
+.navbar-static-top,
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ border-radius: 0;
+}
+@media (max-width: 767px) {
+ .navbar .navbar-nav .open .dropdown-menu > .active > a,
+ .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
+ .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
+ color: #fff;
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+ background-repeat: repeat-x;
+ }
+}
+.alert {
+ text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+}
+.alert-success {
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+ background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #b2dba1;
+}
+.alert-info {
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+ background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #9acfea;
+}
+.alert-warning {
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+ background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #f5e79e;
+}
+.alert-danger {
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+ background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
+ background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #dca7a7;
+}
+.progress {
+ background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+ background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
+ background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar {
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-success {
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+ background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-info {
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+ background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-warning {
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+ background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-danger {
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+ background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-striped {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.list-group {
+ border-radius: 4px;
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+ text-shadow: 0 -1px 0 #286090;
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #2b669a;
+}
+.list-group-item.active .badge,
+.list-group-item.active:hover .badge,
+.list-group-item.active:focus .badge {
+ text-shadow: none;
+}
+.panel {
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+}
+.panel-default > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-primary > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-success > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+ background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-info > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+ background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-warning > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+ background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-danger > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+ background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
+ background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
+ background-repeat: repeat-x;
+}
+.well {
+ background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+ background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
+ background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #dcdcdc;
+ -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+}
+/*# sourceMappingURL=bootstrap-theme.css.map */
diff --git a/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css.map b/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css.map
new file mode 100644
index 00000000..016a8dab
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","bootstrap-theme.css","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"AAcA;;;;;;EAME,0CAAA;ECgDA,6FAAA;EACQ,qFAAA;EC5DT;AFgBC;;;;;;;;;;;;EC2CA,0DAAA;EACQ,kDAAA;EC7CT;AFVD;;;;;;EAiBI,mBAAA;EECH;AFgCC;;EAEE,wBAAA;EE9BH;AFmCD;EGlDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EA+B2C,2BAAA;EAA2B,oBAAA;EExBvE;AFLC;;EAEE,2BAAA;EACA,8BAAA;EEOH;AFJC;;EAEE,2BAAA;EACA,uBAAA;EEMH;AFHC;;EAEE,2BAAA;EACA,wBAAA;EEKH;AFUD;EGnDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EE+BD;AF7BC;;EAEE,2BAAA;EACA,8BAAA;EE+BH;AF5BC;;EAEE,2BAAA;EACA,uBAAA;EE8BH;AF3BC;;EAEE,2BAAA;EACA,wBAAA;EE6BH;AFbD;EGpDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EEuDD;AFrDC;;EAEE,2BAAA;EACA,8BAAA;EEuDH;AFpDC;;EAEE,2BAAA;EACA,uBAAA;EEsDH;AFnDC;;EAEE,2BAAA;EACA,wBAAA;EEqDH;AFpCD;EGrDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EE+ED;AF7EC;;EAEE,2BAAA;EACA,8BAAA;EE+EH;AF5EC;;EAEE,2BAAA;EACA,uBAAA;EE8EH;AF3EC;;EAEE,2BAAA;EACA,wBAAA;EE6EH;AF3DD;EGtDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EEuGD;AFrGC;;EAEE,2BAAA;EACA,8BAAA;EEuGH;AFpGC;;EAEE,2BAAA;EACA,uBAAA;EEsGH;AFnGC;;EAEE,2BAAA;EACA,wBAAA;EEqGH;AFlFD;EGvDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EE+HD;AF7HC;;EAEE,2BAAA;EACA,8BAAA;EE+HH;AF5HC;;EAEE,2BAAA;EACA,uBAAA;EE8HH;AF3HC;;EAEE,2BAAA;EACA,wBAAA;EE6HH;AFnGD;;ECfE,oDAAA;EACQ,4CAAA;ECsHT;AF9FD;;EGxEI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHuEF,2BAAA;EEoGD;AFlGD;;;EG7EI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH6EF,2BAAA;EEwGD;AF/FD;EG1FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EJ4GA,oBAAA;EC9CA,6FAAA;EACQ,qFAAA;ECoJT;AF1GD;;EG1FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,0DAAA;EACQ,kDAAA;EC8JT;AFvGD;;EAEE,gDAAA;EEyGD;AFrGD;EG7GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EFyOD;AF7GD;;EG7GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,yDAAA;EACQ,iDAAA;ECoLT;AFvHD;;EAYI,2CAAA;EE+GH;AF1GD;;;EAGE,kBAAA;EE4GD;AF5FD;EAVI;;;IAGE,aAAA;IG1IF,0EAAA;IACA,qEAAA;IACA,+FAAA;IAAA,wEAAA;IACA,6BAAA;IACA,wHAAA;IDoPD;EACF;AFnGD;EACE,+CAAA;ECxGA,4FAAA;EACQ,oFAAA;EC8MT;AF3FD;EGnKI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH2JF,uBAAA;EEuGD;AFlGD;EGpKI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH2JF,uBAAA;EE+GD;AFzGD;EGrKI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH2JF,uBAAA;EEuHD;AFhHD;EGtKI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH2JF,uBAAA;EE+HD;AFhHD;EG9KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDiSH;AF7GD;EGxLI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDwSH;AFnHD;EGzLI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED+SH;AFzHD;EG1LI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDsTH;AF/HD;EG3LI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED6TH;AFrID;EG5LI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDoUH;AFxID;EG/JI,+MAAA;EACA,0MAAA;EACA,uMAAA;ED0SH;AFpID;EACE,oBAAA;EC3JA,oDAAA;EACQ,4CAAA;ECkST;AFrID;;;EAGE,+BAAA;EGhNE,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8MF,uBAAA;EE2ID;AFhJD;;;EAQI,mBAAA;EE6IH;AFnID;EChLE,mDAAA;EACQ,2CAAA;ECsTT;AF7HD;EGzOI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDyWH;AFnID;EG1OI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDgXH;AFzID;EG3OI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDuXH;AF/ID;EG5OI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED8XH;AFrJD;EG7OI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDqYH;AF3JD;EG9OI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED4YH;AF3JD;EGrPI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHmPF,uBAAA;ECxMA,2FAAA;EACQ,mFAAA;EC0WT","file":"bootstrap-theme.css","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &:disabled,\n &[disabled] {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: #fff;\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n }\n }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // See https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n",".btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n text-shadow: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n}\n.btn-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #dbdbdb;\n text-shadow: 0 1px 0 #fff;\n border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n background-color: #e0e0e0;\n background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n background-color: #e0e0e0;\n border-color: #dbdbdb;\n}\n.btn-default:disabled,\n.btn-default[disabled] {\n background-color: #e0e0e0;\n background-image: none;\n}\n.btn-primary {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #245580;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n background-color: #265a88;\n background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n background-color: #265a88;\n border-color: #245580;\n}\n.btn-primary:disabled,\n.btn-primary[disabled] {\n background-color: #265a88;\n background-image: none;\n}\n.btn-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #3e8f3e;\n}\n.btn-success:hover,\n.btn-success:focus {\n background-color: #419641;\n background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n background-color: #419641;\n border-color: #3e8f3e;\n}\n.btn-success:disabled,\n.btn-success[disabled] {\n background-color: #419641;\n background-image: none;\n}\n.btn-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #28a4c9;\n}\n.btn-info:hover,\n.btn-info:focus {\n background-color: #2aabd2;\n background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n background-color: #2aabd2;\n border-color: #28a4c9;\n}\n.btn-info:disabled,\n.btn-info[disabled] {\n background-color: #2aabd2;\n background-image: none;\n}\n.btn-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #e38d13;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n background-color: #eb9316;\n background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n background-color: #eb9316;\n border-color: #e38d13;\n}\n.btn-warning:disabled,\n.btn-warning[disabled] {\n background-color: #eb9316;\n background-image: none;\n}\n.btn-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #b92c28;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n background-color: #c12e2a;\n background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n background-color: #c12e2a;\n border-color: #b92c28;\n}\n.btn-danger:disabled,\n.btn-danger[disabled] {\n background-color: #c12e2a;\n background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n background-color: #e8e8e8;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n background-color: #2e6da4;\n}\n.navbar-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);\n}\n.navbar-inverse {\n background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%);\n background-image: -o-linear-gradient(top, #3c3c3c 0%, #222222 100%);\n background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n@media (max-width: 767px) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n }\n}\n.alert {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.alert-success {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);\n border-color: #b2dba1;\n}\n.alert-info {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);\n border-color: #9acfea;\n}\n.alert-warning {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);\n border-color: #f5e79e;\n}\n.alert-danger {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);\n border-color: #dca7a7;\n}\n.progress {\n background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n}\n.progress-bar {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);\n}\n.progress-bar-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);\n}\n.progress-bar-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);\n}\n.progress-bar-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);\n}\n.progress-bar-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);\n}\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.list-group {\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 #286090;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);\n border-color: #2b669a;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n text-shadow: none;\n}\n.panel {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.panel-default > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n}\n.panel-primary > .panel-heading {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n}\n.panel-success > .panel-heading {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);\n}\n.panel-info > .panel-heading {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);\n}\n.panel-warning > .panel-heading {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);\n}\n.panel-danger > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);\n}\n.well {\n background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n border-color: #dcdcdc;\n -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} \ No newline at end of file
diff --git a/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.min.css b/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.min.css
new file mode 100644
index 00000000..4c3e7bad
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-default .badge,.btn-primary .badge,.btn-success .badge,.btn-info .badge,.btn-warning .badge,.btn-danger .badge{text-shadow:none}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:hover,.btn-primary:focus{background-color:#265a88;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#265a88;border-color:#245580}.btn-primary:disabled,.btn-primary[disabled]{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:hover .badge,.list-group-item.active:focus .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} \ No newline at end of file
diff --git a/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap.css b/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap.css
new file mode 100644
index 00000000..c6f3d210
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap.css
@@ -0,0 +1,6332 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
+html {
+ font-family: sans-serif;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+}
+body {
+ margin: 0;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+ display: block;
+}
+audio,
+canvas,
+progress,
+video {
+ display: inline-block;
+ vertical-align: baseline;
+}
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+[hidden],
+template {
+ display: none;
+}
+a {
+ background-color: transparent;
+}
+a:active,
+a:hover {
+ outline: 0;
+}
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+b,
+strong {
+ font-weight: bold;
+}
+dfn {
+ font-style: italic;
+}
+h1 {
+ margin: .67em 0;
+ font-size: 2em;
+}
+mark {
+ color: #000;
+ background: #ff0;
+}
+small {
+ font-size: 80%;
+}
+sub,
+sup {
+ position: relative;
+ font-size: 75%;
+ line-height: 0;
+ vertical-align: baseline;
+}
+sup {
+ top: -.5em;
+}
+sub {
+ bottom: -.25em;
+}
+img {
+ border: 0;
+}
+svg:not(:root) {
+ overflow: hidden;
+}
+figure {
+ margin: 1em 40px;
+}
+hr {
+ height: 0;
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+pre {
+ overflow: auto;
+}
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, monospace;
+ font-size: 1em;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+ margin: 0;
+ font: inherit;
+ color: inherit;
+}
+button {
+ overflow: visible;
+}
+button,
+select {
+ text-transform: none;
+}
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button;
+ cursor: pointer;
+}
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+input {
+ line-height: normal;
+}
+input[type="checkbox"],
+input[type="radio"] {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 0;
+}
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+input[type="search"] {
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ -webkit-appearance: textfield;
+}
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+fieldset {
+ padding: .35em .625em .75em;
+ margin: 0 2px;
+ border: 1px solid #c0c0c0;
+}
+legend {
+ padding: 0;
+ border: 0;
+}
+textarea {
+ overflow: auto;
+}
+optgroup {
+ font-weight: bold;
+}
+table {
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+td,
+th {
+ padding: 0;
+}
+/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
+@media print {
+ *,
+ *:before,
+ *:after {
+ color: #000 !important;
+ text-shadow: none !important;
+ background: transparent !important;
+ -webkit-box-shadow: none !important;
+ box-shadow: none !important;
+ }
+ a,
+ a:visited {
+ text-decoration: underline;
+ }
+ a[href]:after {
+ content: " (" attr(href) ")";
+ }
+ abbr[title]:after {
+ content: " (" attr(title) ")";
+ }
+ a[href^="#"]:after,
+ a[href^="javascript:"]:after {
+ content: "";
+ }
+ pre,
+ blockquote {
+ border: 1px solid #999;
+
+ page-break-inside: avoid;
+ }
+ thead {
+ display: table-header-group;
+ }
+ tr,
+ img {
+ page-break-inside: avoid;
+ }
+ img {
+ max-width: 100% !important;
+ }
+ p,
+ h2,
+ h3 {
+ orphans: 3;
+ widows: 3;
+ }
+ h2,
+ h3 {
+ page-break-after: avoid;
+ }
+ select {
+ background: #fff !important;
+ }
+ .navbar {
+ display: none;
+ }
+ .btn > .caret,
+ .dropup > .btn > .caret {
+ border-top-color: #000 !important;
+ }
+ .label {
+ border: 1px solid #000;
+ }
+ .table {
+ border-collapse: collapse !important;
+ }
+ .table td,
+ .table th {
+ background-color: #fff !important;
+ }
+ .table-bordered th,
+ .table-bordered td {
+ border: 1px solid #ddd !important;
+ }
+}
+@font-face {
+ font-family: 'Glyphicons Halflings';
+
+ src: url('../fonts/glyphicons-halflings-regular.eot');
+ src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
+}
+.glyphicon {
+ position: relative;
+ top: 1px;
+ display: inline-block;
+ font-family: 'Glyphicons Halflings';
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+.glyphicon-asterisk:before {
+ content: "\2a";
+}
+.glyphicon-plus:before {
+ content: "\2b";
+}
+.glyphicon-euro:before,
+.glyphicon-eur:before {
+ content: "\20ac";
+}
+.glyphicon-minus:before {
+ content: "\2212";
+}
+.glyphicon-cloud:before {
+ content: "\2601";
+}
+.glyphicon-envelope:before {
+ content: "\2709";
+}
+.glyphicon-pencil:before {
+ content: "\270f";
+}
+.glyphicon-glass:before {
+ content: "\e001";
+}
+.glyphicon-music:before {
+ content: "\e002";
+}
+.glyphicon-search:before {
+ content: "\e003";
+}
+.glyphicon-heart:before {
+ content: "\e005";
+}
+.glyphicon-star:before {
+ content: "\e006";
+}
+.glyphicon-star-empty:before {
+ content: "\e007";
+}
+.glyphicon-user:before {
+ content: "\e008";
+}
+.glyphicon-film:before {
+ content: "\e009";
+}
+.glyphicon-th-large:before {
+ content: "\e010";
+}
+.glyphicon-th:before {
+ content: "\e011";
+}
+.glyphicon-th-list:before {
+ content: "\e012";
+}
+.glyphicon-ok:before {
+ content: "\e013";
+}
+.glyphicon-remove:before {
+ content: "\e014";
+}
+.glyphicon-zoom-in:before {
+ content: "\e015";
+}
+.glyphicon-zoom-out:before {
+ content: "\e016";
+}
+.glyphicon-off:before {
+ content: "\e017";
+}
+.glyphicon-signal:before {
+ content: "\e018";
+}
+.glyphicon-cog:before {
+ content: "\e019";
+}
+.glyphicon-trash:before {
+ content: "\e020";
+}
+.glyphicon-home:before {
+ content: "\e021";
+}
+.glyphicon-file:before {
+ content: "\e022";
+}
+.glyphicon-time:before {
+ content: "\e023";
+}
+.glyphicon-road:before {
+ content: "\e024";
+}
+.glyphicon-download-alt:before {
+ content: "\e025";
+}
+.glyphicon-download:before {
+ content: "\e026";
+}
+.glyphicon-upload:before {
+ content: "\e027";
+}
+.glyphicon-inbox:before {
+ content: "\e028";
+}
+.glyphicon-play-circle:before {
+ content: "\e029";
+}
+.glyphicon-repeat:before {
+ content: "\e030";
+}
+.glyphicon-refresh:before {
+ content: "\e031";
+}
+.glyphicon-list-alt:before {
+ content: "\e032";
+}
+.glyphicon-lock:before {
+ content: "\e033";
+}
+.glyphicon-flag:before {
+ content: "\e034";
+}
+.glyphicon-headphones:before {
+ content: "\e035";
+}
+.glyphicon-volume-off:before {
+ content: "\e036";
+}
+.glyphicon-volume-down:before {
+ content: "\e037";
+}
+.glyphicon-volume-up:before {
+ content: "\e038";
+}
+.glyphicon-qrcode:before {
+ content: "\e039";
+}
+.glyphicon-barcode:before {
+ content: "\e040";
+}
+.glyphicon-tag:before {
+ content: "\e041";
+}
+.glyphicon-tags:before {
+ content: "\e042";
+}
+.glyphicon-book:before {
+ content: "\e043";
+}
+.glyphicon-bookmark:before {
+ content: "\e044";
+}
+.glyphicon-print:before {
+ content: "\e045";
+}
+.glyphicon-camera:before {
+ content: "\e046";
+}
+.glyphicon-font:before {
+ content: "\e047";
+}
+.glyphicon-bold:before {
+ content: "\e048";
+}
+.glyphicon-italic:before {
+ content: "\e049";
+}
+.glyphicon-text-height:before {
+ content: "\e050";
+}
+.glyphicon-text-width:before {
+ content: "\e051";
+}
+.glyphicon-align-left:before {
+ content: "\e052";
+}
+.glyphicon-align-center:before {
+ content: "\e053";
+}
+.glyphicon-align-right:before {
+ content: "\e054";
+}
+.glyphicon-align-justify:before {
+ content: "\e055";
+}
+.glyphicon-list:before {
+ content: "\e056";
+}
+.glyphicon-indent-left:before {
+ content: "\e057";
+}
+.glyphicon-indent-right:before {
+ content: "\e058";
+}
+.glyphicon-facetime-video:before {
+ content: "\e059";
+}
+.glyphicon-picture:before {
+ content: "\e060";
+}
+.glyphicon-map-marker:before {
+ content: "\e062";
+}
+.glyphicon-adjust:before {
+ content: "\e063";
+}
+.glyphicon-tint:before {
+ content: "\e064";
+}
+.glyphicon-edit:before {
+ content: "\e065";
+}
+.glyphicon-share:before {
+ content: "\e066";
+}
+.glyphicon-check:before {
+ content: "\e067";
+}
+.glyphicon-move:before {
+ content: "\e068";
+}
+.glyphicon-step-backward:before {
+ content: "\e069";
+}
+.glyphicon-fast-backward:before {
+ content: "\e070";
+}
+.glyphicon-backward:before {
+ content: "\e071";
+}
+.glyphicon-play:before {
+ content: "\e072";
+}
+.glyphicon-pause:before {
+ content: "\e073";
+}
+.glyphicon-stop:before {
+ content: "\e074";
+}
+.glyphicon-forward:before {
+ content: "\e075";
+}
+.glyphicon-fast-forward:before {
+ content: "\e076";
+}
+.glyphicon-step-forward:before {
+ content: "\e077";
+}
+.glyphicon-eject:before {
+ content: "\e078";
+}
+.glyphicon-chevron-left:before {
+ content: "\e079";
+}
+.glyphicon-chevron-right:before {
+ content: "\e080";
+}
+.glyphicon-plus-sign:before {
+ content: "\e081";
+}
+.glyphicon-minus-sign:before {
+ content: "\e082";
+}
+.glyphicon-remove-sign:before {
+ content: "\e083";
+}
+.glyphicon-ok-sign:before {
+ content: "\e084";
+}
+.glyphicon-question-sign:before {
+ content: "\e085";
+}
+.glyphicon-info-sign:before {
+ content: "\e086";
+}
+.glyphicon-screenshot:before {
+ content: "\e087";
+}
+.glyphicon-remove-circle:before {
+ content: "\e088";
+}
+.glyphicon-ok-circle:before {
+ content: "\e089";
+}
+.glyphicon-ban-circle:before {
+ content: "\e090";
+}
+.glyphicon-arrow-left:before {
+ content: "\e091";
+}
+.glyphicon-arrow-right:before {
+ content: "\e092";
+}
+.glyphicon-arrow-up:before {
+ content: "\e093";
+}
+.glyphicon-arrow-down:before {
+ content: "\e094";
+}
+.glyphicon-share-alt:before {
+ content: "\e095";
+}
+.glyphicon-resize-full:before {
+ content: "\e096";
+}
+.glyphicon-resize-small:before {
+ content: "\e097";
+}
+.glyphicon-exclamation-sign:before {
+ content: "\e101";
+}
+.glyphicon-gift:before {
+ content: "\e102";
+}
+.glyphicon-leaf:before {
+ content: "\e103";
+}
+.glyphicon-fire:before {
+ content: "\e104";
+}
+.glyphicon-eye-open:before {
+ content: "\e105";
+}
+.glyphicon-eye-close:before {
+ content: "\e106";
+}
+.glyphicon-warning-sign:before {
+ content: "\e107";
+}
+.glyphicon-plane:before {
+ content: "\e108";
+}
+.glyphicon-calendar:before {
+ content: "\e109";
+}
+.glyphicon-random:before {
+ content: "\e110";
+}
+.glyphicon-comment:before {
+ content: "\e111";
+}
+.glyphicon-magnet:before {
+ content: "\e112";
+}
+.glyphicon-chevron-up:before {
+ content: "\e113";
+}
+.glyphicon-chevron-down:before {
+ content: "\e114";
+}
+.glyphicon-retweet:before {
+ content: "\e115";
+}
+.glyphicon-shopping-cart:before {
+ content: "\e116";
+}
+.glyphicon-folder-close:before {
+ content: "\e117";
+}
+.glyphicon-folder-open:before {
+ content: "\e118";
+}
+.glyphicon-resize-vertical:before {
+ content: "\e119";
+}
+.glyphicon-resize-horizontal:before {
+ content: "\e120";
+}
+.glyphicon-hdd:before {
+ content: "\e121";
+}
+.glyphicon-bullhorn:before {
+ content: "\e122";
+}
+.glyphicon-bell:before {
+ content: "\e123";
+}
+.glyphicon-certificate:before {
+ content: "\e124";
+}
+.glyphicon-thumbs-up:before {
+ content: "\e125";
+}
+.glyphicon-thumbs-down:before {
+ content: "\e126";
+}
+.glyphicon-hand-right:before {
+ content: "\e127";
+}
+.glyphicon-hand-left:before {
+ content: "\e128";
+}
+.glyphicon-hand-up:before {
+ content: "\e129";
+}
+.glyphicon-hand-down:before {
+ content: "\e130";
+}
+.glyphicon-circle-arrow-right:before {
+ content: "\e131";
+}
+.glyphicon-circle-arrow-left:before {
+ content: "\e132";
+}
+.glyphicon-circle-arrow-up:before {
+ content: "\e133";
+}
+.glyphicon-circle-arrow-down:before {
+ content: "\e134";
+}
+.glyphicon-globe:before {
+ content: "\e135";
+}
+.glyphicon-wrench:before {
+ content: "\e136";
+}
+.glyphicon-tasks:before {
+ content: "\e137";
+}
+.glyphicon-filter:before {
+ content: "\e138";
+}
+.glyphicon-briefcase:before {
+ content: "\e139";
+}
+.glyphicon-fullscreen:before {
+ content: "\e140";
+}
+.glyphicon-dashboard:before {
+ content: "\e141";
+}
+.glyphicon-paperclip:before {
+ content: "\e142";
+}
+.glyphicon-heart-empty:before {
+ content: "\e143";
+}
+.glyphicon-link:before {
+ content: "\e144";
+}
+.glyphicon-phone:before {
+ content: "\e145";
+}
+.glyphicon-pushpin:before {
+ content: "\e146";
+}
+.glyphicon-usd:before {
+ content: "\e148";
+}
+.glyphicon-gbp:before {
+ content: "\e149";
+}
+.glyphicon-sort:before {
+ content: "\e150";
+}
+.glyphicon-sort-by-alphabet:before {
+ content: "\e151";
+}
+.glyphicon-sort-by-alphabet-alt:before {
+ content: "\e152";
+}
+.glyphicon-sort-by-order:before {
+ content: "\e153";
+}
+.glyphicon-sort-by-order-alt:before {
+ content: "\e154";
+}
+.glyphicon-sort-by-attributes:before {
+ content: "\e155";
+}
+.glyphicon-sort-by-attributes-alt:before {
+ content: "\e156";
+}
+.glyphicon-unchecked:before {
+ content: "\e157";
+}
+.glyphicon-expand:before {
+ content: "\e158";
+}
+.glyphicon-collapse-down:before {
+ content: "\e159";
+}
+.glyphicon-collapse-up:before {
+ content: "\e160";
+}
+.glyphicon-log-in:before {
+ content: "\e161";
+}
+.glyphicon-flash:before {
+ content: "\e162";
+}
+.glyphicon-log-out:before {
+ content: "\e163";
+}
+.glyphicon-new-window:before {
+ content: "\e164";
+}
+.glyphicon-record:before {
+ content: "\e165";
+}
+.glyphicon-save:before {
+ content: "\e166";
+}
+.glyphicon-open:before {
+ content: "\e167";
+}
+.glyphicon-saved:before {
+ content: "\e168";
+}
+.glyphicon-import:before {
+ content: "\e169";
+}
+.glyphicon-export:before {
+ content: "\e170";
+}
+.glyphicon-send:before {
+ content: "\e171";
+}
+.glyphicon-floppy-disk:before {
+ content: "\e172";
+}
+.glyphicon-floppy-saved:before {
+ content: "\e173";
+}
+.glyphicon-floppy-remove:before {
+ content: "\e174";
+}
+.glyphicon-floppy-save:before {
+ content: "\e175";
+}
+.glyphicon-floppy-open:before {
+ content: "\e176";
+}
+.glyphicon-credit-card:before {
+ content: "\e177";
+}
+.glyphicon-transfer:before {
+ content: "\e178";
+}
+.glyphicon-cutlery:before {
+ content: "\e179";
+}
+.glyphicon-header:before {
+ content: "\e180";
+}
+.glyphicon-compressed:before {
+ content: "\e181";
+}
+.glyphicon-earphone:before {
+ content: "\e182";
+}
+.glyphicon-phone-alt:before {
+ content: "\e183";
+}
+.glyphicon-tower:before {
+ content: "\e184";
+}
+.glyphicon-stats:before {
+ content: "\e185";
+}
+.glyphicon-sd-video:before {
+ content: "\e186";
+}
+.glyphicon-hd-video:before {
+ content: "\e187";
+}
+.glyphicon-subtitles:before {
+ content: "\e188";
+}
+.glyphicon-sound-stereo:before {
+ content: "\e189";
+}
+.glyphicon-sound-dolby:before {
+ content: "\e190";
+}
+.glyphicon-sound-5-1:before {
+ content: "\e191";
+}
+.glyphicon-sound-6-1:before {
+ content: "\e192";
+}
+.glyphicon-sound-7-1:before {
+ content: "\e193";
+}
+.glyphicon-copyright-mark:before {
+ content: "\e194";
+}
+.glyphicon-registration-mark:before {
+ content: "\e195";
+}
+.glyphicon-cloud-download:before {
+ content: "\e197";
+}
+.glyphicon-cloud-upload:before {
+ content: "\e198";
+}
+.glyphicon-tree-conifer:before {
+ content: "\e199";
+}
+.glyphicon-tree-deciduous:before {
+ content: "\e200";
+}
+* {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+*:before,
+*:after {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+html {
+ font-size: 10px;
+
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+body {
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #333;
+ background-color: #fff;
+}
+input,
+button,
+select,
+textarea {
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+}
+a {
+ color: #337ab7;
+ text-decoration: none;
+}
+a:hover,
+a:focus {
+ color: #23527c;
+ text-decoration: underline;
+}
+a:focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+figure {
+ margin: 0;
+}
+img {
+ vertical-align: middle;
+}
+.img-responsive,
+.thumbnail > img,
+.thumbnail a > img,
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+ display: block;
+ max-width: 100%;
+ height: auto;
+}
+.img-rounded {
+ border-radius: 6px;
+}
+.img-thumbnail {
+ display: inline-block;
+ max-width: 100%;
+ height: auto;
+ padding: 4px;
+ line-height: 1.42857143;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ -webkit-transition: all .2s ease-in-out;
+ -o-transition: all .2s ease-in-out;
+ transition: all .2s ease-in-out;
+}
+.img-circle {
+ border-radius: 50%;
+}
+hr {
+ margin-top: 20px;
+ margin-bottom: 20px;
+ border: 0;
+ border-top: 1px solid #eee;
+}
+.sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ border: 0;
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+ position: static;
+ width: auto;
+ height: auto;
+ margin: 0;
+ overflow: visible;
+ clip: auto;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6 {
+ font-family: inherit;
+ font-weight: 500;
+ line-height: 1.1;
+ color: inherit;
+}
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small,
+.h1 small,
+.h2 small,
+.h3 small,
+.h4 small,
+.h5 small,
+.h6 small,
+h1 .small,
+h2 .small,
+h3 .small,
+h4 .small,
+h5 .small,
+h6 .small,
+.h1 .small,
+.h2 .small,
+.h3 .small,
+.h4 .small,
+.h5 .small,
+.h6 .small {
+ font-weight: normal;
+ line-height: 1;
+ color: #777;
+}
+h1,
+.h1,
+h2,
+.h2,
+h3,
+.h3 {
+ margin-top: 20px;
+ margin-bottom: 10px;
+}
+h1 small,
+.h1 small,
+h2 small,
+.h2 small,
+h3 small,
+.h3 small,
+h1 .small,
+.h1 .small,
+h2 .small,
+.h2 .small,
+h3 .small,
+.h3 .small {
+ font-size: 65%;
+}
+h4,
+.h4,
+h5,
+.h5,
+h6,
+.h6 {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+h4 small,
+.h4 small,
+h5 small,
+.h5 small,
+h6 small,
+.h6 small,
+h4 .small,
+.h4 .small,
+h5 .small,
+.h5 .small,
+h6 .small,
+.h6 .small {
+ font-size: 75%;
+}
+h1,
+.h1 {
+ font-size: 36px;
+}
+h2,
+.h2 {
+ font-size: 30px;
+}
+h3,
+.h3 {
+ font-size: 24px;
+}
+h4,
+.h4 {
+ font-size: 18px;
+}
+h5,
+.h5 {
+ font-size: 14px;
+}
+h6,
+.h6 {
+ font-size: 12px;
+}
+p {
+ margin: 0 0 10px;
+}
+.lead {
+ margin-bottom: 20px;
+ font-size: 16px;
+ font-weight: 300;
+ line-height: 1.4;
+}
+@media (min-width: 768px) {
+ .lead {
+ font-size: 21px;
+ }
+}
+small,
+.small {
+ font-size: 85%;
+}
+mark,
+.mark {
+ padding: .2em;
+ background-color: #fcf8e3;
+}
+.text-left {
+ text-align: left;
+}
+.text-right {
+ text-align: right;
+}
+.text-center {
+ text-align: center;
+}
+.text-justify {
+ text-align: justify;
+}
+.text-nowrap {
+ white-space: nowrap;
+}
+.text-lowercase {
+ text-transform: lowercase;
+}
+.text-uppercase {
+ text-transform: uppercase;
+}
+.text-capitalize {
+ text-transform: capitalize;
+}
+.text-muted {
+ color: #777;
+}
+.text-primary {
+ color: #337ab7;
+}
+a.text-primary:hover {
+ color: #286090;
+}
+.text-success {
+ color: #3c763d;
+}
+a.text-success:hover {
+ color: #2b542c;
+}
+.text-info {
+ color: #31708f;
+}
+a.text-info:hover {
+ color: #245269;
+}
+.text-warning {
+ color: #8a6d3b;
+}
+a.text-warning:hover {
+ color: #66512c;
+}
+.text-danger {
+ color: #a94442;
+}
+a.text-danger:hover {
+ color: #843534;
+}
+.bg-primary {
+ color: #fff;
+ background-color: #337ab7;
+}
+a.bg-primary:hover {
+ background-color: #286090;
+}
+.bg-success {
+ background-color: #dff0d8;
+}
+a.bg-success:hover {
+ background-color: #c1e2b3;
+}
+.bg-info {
+ background-color: #d9edf7;
+}
+a.bg-info:hover {
+ background-color: #afd9ee;
+}
+.bg-warning {
+ background-color: #fcf8e3;
+}
+a.bg-warning:hover {
+ background-color: #f7ecb5;
+}
+.bg-danger {
+ background-color: #f2dede;
+}
+a.bg-danger:hover {
+ background-color: #e4b9b9;
+}
+.page-header {
+ padding-bottom: 9px;
+ margin: 40px 0 20px;
+ border-bottom: 1px solid #eee;
+}
+ul,
+ol {
+ margin-top: 0;
+ margin-bottom: 10px;
+}
+ul ul,
+ol ul,
+ul ol,
+ol ol {
+ margin-bottom: 0;
+}
+.list-unstyled {
+ padding-left: 0;
+ list-style: none;
+}
+.list-inline {
+ padding-left: 0;
+ margin-left: -5px;
+ list-style: none;
+}
+.list-inline > li {
+ display: inline-block;
+ padding-right: 5px;
+ padding-left: 5px;
+}
+dl {
+ margin-top: 0;
+ margin-bottom: 20px;
+}
+dt,
+dd {
+ line-height: 1.42857143;
+}
+dt {
+ font-weight: bold;
+}
+dd {
+ margin-left: 0;
+}
+@media (min-width: 768px) {
+ .dl-horizontal dt {
+ float: left;
+ width: 160px;
+ overflow: hidden;
+ clear: left;
+ text-align: right;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ .dl-horizontal dd {
+ margin-left: 180px;
+ }
+}
+abbr[title],
+abbr[data-original-title] {
+ cursor: help;
+ border-bottom: 1px dotted #777;
+}
+.initialism {
+ font-size: 90%;
+ text-transform: uppercase;
+}
+blockquote {
+ padding: 10px 20px;
+ margin: 0 0 20px;
+ font-size: 17.5px;
+ border-left: 5px solid #eee;
+}
+blockquote p:last-child,
+blockquote ul:last-child,
+blockquote ol:last-child {
+ margin-bottom: 0;
+}
+blockquote footer,
+blockquote small,
+blockquote .small {
+ display: block;
+ font-size: 80%;
+ line-height: 1.42857143;
+ color: #777;
+}
+blockquote footer:before,
+blockquote small:before,
+blockquote .small:before {
+ content: '\2014 \00A0';
+}
+.blockquote-reverse,
+blockquote.pull-right {
+ padding-right: 15px;
+ padding-left: 0;
+ text-align: right;
+ border-right: 5px solid #eee;
+ border-left: 0;
+}
+.blockquote-reverse footer:before,
+blockquote.pull-right footer:before,
+.blockquote-reverse small:before,
+blockquote.pull-right small:before,
+.blockquote-reverse .small:before,
+blockquote.pull-right .small:before {
+ content: '';
+}
+.blockquote-reverse footer:after,
+blockquote.pull-right footer:after,
+.blockquote-reverse small:after,
+blockquote.pull-right small:after,
+.blockquote-reverse .small:after,
+blockquote.pull-right .small:after {
+ content: '\00A0 \2014';
+}
+address {
+ margin-bottom: 20px;
+ font-style: normal;
+ line-height: 1.42857143;
+}
+code,
+kbd,
+pre,
+samp {
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+}
+code {
+ padding: 2px 4px;
+ font-size: 90%;
+ color: #c7254e;
+ background-color: #f9f2f4;
+ border-radius: 4px;
+}
+kbd {
+ padding: 2px 4px;
+ font-size: 90%;
+ color: #fff;
+ background-color: #333;
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
+}
+kbd kbd {
+ padding: 0;
+ font-size: 100%;
+ font-weight: bold;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+pre {
+ display: block;
+ padding: 9.5px;
+ margin: 0 0 10px;
+ font-size: 13px;
+ line-height: 1.42857143;
+ color: #333;
+ word-break: break-all;
+ word-wrap: break-word;
+ background-color: #f5f5f5;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+}
+pre code {
+ padding: 0;
+ font-size: inherit;
+ color: inherit;
+ white-space: pre-wrap;
+ background-color: transparent;
+ border-radius: 0;
+}
+.pre-scrollable {
+ max-height: 340px;
+ overflow-y: scroll;
+}
+.container {
+ padding-right: 15px;
+ padding-left: 15px;
+ margin-right: auto;
+ margin-left: auto;
+}
+@media (min-width: 768px) {
+ .container {
+ width: 750px;
+ }
+}
+@media (min-width: 992px) {
+ .container {
+ width: 970px;
+ }
+}
+@media (min-width: 1200px) {
+ .container {
+ width: 1170px;
+ }
+}
+.container-fluid {
+ padding-right: 15px;
+ padding-left: 15px;
+ margin-right: auto;
+ margin-left: auto;
+}
+.row {
+ margin-right: -15px;
+ margin-left: -15px;
+}
+.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
+ position: relative;
+ min-height: 1px;
+ padding-right: 15px;
+ padding-left: 15px;
+}
+.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
+ float: left;
+}
+.col-xs-12 {
+ width: 100%;
+}
+.col-xs-11 {
+ width: 91.66666667%;
+}
+.col-xs-10 {
+ width: 83.33333333%;
+}
+.col-xs-9 {
+ width: 75%;
+}
+.col-xs-8 {
+ width: 66.66666667%;
+}
+.col-xs-7 {
+ width: 58.33333333%;
+}
+.col-xs-6 {
+ width: 50%;
+}
+.col-xs-5 {
+ width: 41.66666667%;
+}
+.col-xs-4 {
+ width: 33.33333333%;
+}
+.col-xs-3 {
+ width: 25%;
+}
+.col-xs-2 {
+ width: 16.66666667%;
+}
+.col-xs-1 {
+ width: 8.33333333%;
+}
+.col-xs-pull-12 {
+ right: 100%;
+}
+.col-xs-pull-11 {
+ right: 91.66666667%;
+}
+.col-xs-pull-10 {
+ right: 83.33333333%;
+}
+.col-xs-pull-9 {
+ right: 75%;
+}
+.col-xs-pull-8 {
+ right: 66.66666667%;
+}
+.col-xs-pull-7 {
+ right: 58.33333333%;
+}
+.col-xs-pull-6 {
+ right: 50%;
+}
+.col-xs-pull-5 {
+ right: 41.66666667%;
+}
+.col-xs-pull-4 {
+ right: 33.33333333%;
+}
+.col-xs-pull-3 {
+ right: 25%;
+}
+.col-xs-pull-2 {
+ right: 16.66666667%;
+}
+.col-xs-pull-1 {
+ right: 8.33333333%;
+}
+.col-xs-pull-0 {
+ right: auto;
+}
+.col-xs-push-12 {
+ left: 100%;
+}
+.col-xs-push-11 {
+ left: 91.66666667%;
+}
+.col-xs-push-10 {
+ left: 83.33333333%;
+}
+.col-xs-push-9 {
+ left: 75%;
+}
+.col-xs-push-8 {
+ left: 66.66666667%;
+}
+.col-xs-push-7 {
+ left: 58.33333333%;
+}
+.col-xs-push-6 {
+ left: 50%;
+}
+.col-xs-push-5 {
+ left: 41.66666667%;
+}
+.col-xs-push-4 {
+ left: 33.33333333%;
+}
+.col-xs-push-3 {
+ left: 25%;
+}
+.col-xs-push-2 {
+ left: 16.66666667%;
+}
+.col-xs-push-1 {
+ left: 8.33333333%;
+}
+.col-xs-push-0 {
+ left: auto;
+}
+.col-xs-offset-12 {
+ margin-left: 100%;
+}
+.col-xs-offset-11 {
+ margin-left: 91.66666667%;
+}
+.col-xs-offset-10 {
+ margin-left: 83.33333333%;
+}
+.col-xs-offset-9 {
+ margin-left: 75%;
+}
+.col-xs-offset-8 {
+ margin-left: 66.66666667%;
+}
+.col-xs-offset-7 {
+ margin-left: 58.33333333%;
+}
+.col-xs-offset-6 {
+ margin-left: 50%;
+}
+.col-xs-offset-5 {
+ margin-left: 41.66666667%;
+}
+.col-xs-offset-4 {
+ margin-left: 33.33333333%;
+}
+.col-xs-offset-3 {
+ margin-left: 25%;
+}
+.col-xs-offset-2 {
+ margin-left: 16.66666667%;
+}
+.col-xs-offset-1 {
+ margin-left: 8.33333333%;
+}
+.col-xs-offset-0 {
+ margin-left: 0;
+}
+@media (min-width: 768px) {
+ .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
+ float: left;
+ }
+ .col-sm-12 {
+ width: 100%;
+ }
+ .col-sm-11 {
+ width: 91.66666667%;
+ }
+ .col-sm-10 {
+ width: 83.33333333%;
+ }
+ .col-sm-9 {
+ width: 75%;
+ }
+ .col-sm-8 {
+ width: 66.66666667%;
+ }
+ .col-sm-7 {
+ width: 58.33333333%;
+ }
+ .col-sm-6 {
+ width: 50%;
+ }
+ .col-sm-5 {
+ width: 41.66666667%;
+ }
+ .col-sm-4 {
+ width: 33.33333333%;
+ }
+ .col-sm-3 {
+ width: 25%;
+ }
+ .col-sm-2 {
+ width: 16.66666667%;
+ }
+ .col-sm-1 {
+ width: 8.33333333%;
+ }
+ .col-sm-pull-12 {
+ right: 100%;
+ }
+ .col-sm-pull-11 {
+ right: 91.66666667%;
+ }
+ .col-sm-pull-10 {
+ right: 83.33333333%;
+ }
+ .col-sm-pull-9 {
+ right: 75%;
+ }
+ .col-sm-pull-8 {
+ right: 66.66666667%;
+ }
+ .col-sm-pull-7 {
+ right: 58.33333333%;
+ }
+ .col-sm-pull-6 {
+ right: 50%;
+ }
+ .col-sm-pull-5 {
+ right: 41.66666667%;
+ }
+ .col-sm-pull-4 {
+ right: 33.33333333%;
+ }
+ .col-sm-pull-3 {
+ right: 25%;
+ }
+ .col-sm-pull-2 {
+ right: 16.66666667%;
+ }
+ .col-sm-pull-1 {
+ right: 8.33333333%;
+ }
+ .col-sm-pull-0 {
+ right: auto;
+ }
+ .col-sm-push-12 {
+ left: 100%;
+ }
+ .col-sm-push-11 {
+ left: 91.66666667%;
+ }
+ .col-sm-push-10 {
+ left: 83.33333333%;
+ }
+ .col-sm-push-9 {
+ left: 75%;
+ }
+ .col-sm-push-8 {
+ left: 66.66666667%;
+ }
+ .col-sm-push-7 {
+ left: 58.33333333%;
+ }
+ .col-sm-push-6 {
+ left: 50%;
+ }
+ .col-sm-push-5 {
+ left: 41.66666667%;
+ }
+ .col-sm-push-4 {
+ left: 33.33333333%;
+ }
+ .col-sm-push-3 {
+ left: 25%;
+ }
+ .col-sm-push-2 {
+ left: 16.66666667%;
+ }
+ .col-sm-push-1 {
+ left: 8.33333333%;
+ }
+ .col-sm-push-0 {
+ left: auto;
+ }
+ .col-sm-offset-12 {
+ margin-left: 100%;
+ }
+ .col-sm-offset-11 {
+ margin-left: 91.66666667%;
+ }
+ .col-sm-offset-10 {
+ margin-left: 83.33333333%;
+ }
+ .col-sm-offset-9 {
+ margin-left: 75%;
+ }
+ .col-sm-offset-8 {
+ margin-left: 66.66666667%;
+ }
+ .col-sm-offset-7 {
+ margin-left: 58.33333333%;
+ }
+ .col-sm-offset-6 {
+ margin-left: 50%;
+ }
+ .col-sm-offset-5 {
+ margin-left: 41.66666667%;
+ }
+ .col-sm-offset-4 {
+ margin-left: 33.33333333%;
+ }
+ .col-sm-offset-3 {
+ margin-left: 25%;
+ }
+ .col-sm-offset-2 {
+ margin-left: 16.66666667%;
+ }
+ .col-sm-offset-1 {
+ margin-left: 8.33333333%;
+ }
+ .col-sm-offset-0 {
+ margin-left: 0;
+ }
+}
+@media (min-width: 992px) {
+ .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
+ float: left;
+ }
+ .col-md-12 {
+ width: 100%;
+ }
+ .col-md-11 {
+ width: 91.66666667%;
+ }
+ .col-md-10 {
+ width: 83.33333333%;
+ }
+ .col-md-9 {
+ width: 75%;
+ }
+ .col-md-8 {
+ width: 66.66666667%;
+ }
+ .col-md-7 {
+ width: 58.33333333%;
+ }
+ .col-md-6 {
+ width: 50%;
+ }
+ .col-md-5 {
+ width: 41.66666667%;
+ }
+ .col-md-4 {
+ width: 33.33333333%;
+ }
+ .col-md-3 {
+ width: 25%;
+ }
+ .col-md-2 {
+ width: 16.66666667%;
+ }
+ .col-md-1 {
+ width: 8.33333333%;
+ }
+ .col-md-pull-12 {
+ right: 100%;
+ }
+ .col-md-pull-11 {
+ right: 91.66666667%;
+ }
+ .col-md-pull-10 {
+ right: 83.33333333%;
+ }
+ .col-md-pull-9 {
+ right: 75%;
+ }
+ .col-md-pull-8 {
+ right: 66.66666667%;
+ }
+ .col-md-pull-7 {
+ right: 58.33333333%;
+ }
+ .col-md-pull-6 {
+ right: 50%;
+ }
+ .col-md-pull-5 {
+ right: 41.66666667%;
+ }
+ .col-md-pull-4 {
+ right: 33.33333333%;
+ }
+ .col-md-pull-3 {
+ right: 25%;
+ }
+ .col-md-pull-2 {
+ right: 16.66666667%;
+ }
+ .col-md-pull-1 {
+ right: 8.33333333%;
+ }
+ .col-md-pull-0 {
+ right: auto;
+ }
+ .col-md-push-12 {
+ left: 100%;
+ }
+ .col-md-push-11 {
+ left: 91.66666667%;
+ }
+ .col-md-push-10 {
+ left: 83.33333333%;
+ }
+ .col-md-push-9 {
+ left: 75%;
+ }
+ .col-md-push-8 {
+ left: 66.66666667%;
+ }
+ .col-md-push-7 {
+ left: 58.33333333%;
+ }
+ .col-md-push-6 {
+ left: 50%;
+ }
+ .col-md-push-5 {
+ left: 41.66666667%;
+ }
+ .col-md-push-4 {
+ left: 33.33333333%;
+ }
+ .col-md-push-3 {
+ left: 25%;
+ }
+ .col-md-push-2 {
+ left: 16.66666667%;
+ }
+ .col-md-push-1 {
+ left: 8.33333333%;
+ }
+ .col-md-push-0 {
+ left: auto;
+ }
+ .col-md-offset-12 {
+ margin-left: 100%;
+ }
+ .col-md-offset-11 {
+ margin-left: 91.66666667%;
+ }
+ .col-md-offset-10 {
+ margin-left: 83.33333333%;
+ }
+ .col-md-offset-9 {
+ margin-left: 75%;
+ }
+ .col-md-offset-8 {
+ margin-left: 66.66666667%;
+ }
+ .col-md-offset-7 {
+ margin-left: 58.33333333%;
+ }
+ .col-md-offset-6 {
+ margin-left: 50%;
+ }
+ .col-md-offset-5 {
+ margin-left: 41.66666667%;
+ }
+ .col-md-offset-4 {
+ margin-left: 33.33333333%;
+ }
+ .col-md-offset-3 {
+ margin-left: 25%;
+ }
+ .col-md-offset-2 {
+ margin-left: 16.66666667%;
+ }
+ .col-md-offset-1 {
+ margin-left: 8.33333333%;
+ }
+ .col-md-offset-0 {
+ margin-left: 0;
+ }
+}
+@media (min-width: 1200px) {
+ .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
+ float: left;
+ }
+ .col-lg-12 {
+ width: 100%;
+ }
+ .col-lg-11 {
+ width: 91.66666667%;
+ }
+ .col-lg-10 {
+ width: 83.33333333%;
+ }
+ .col-lg-9 {
+ width: 75%;
+ }
+ .col-lg-8 {
+ width: 66.66666667%;
+ }
+ .col-lg-7 {
+ width: 58.33333333%;
+ }
+ .col-lg-6 {
+ width: 50%;
+ }
+ .col-lg-5 {
+ width: 41.66666667%;
+ }
+ .col-lg-4 {
+ width: 33.33333333%;
+ }
+ .col-lg-3 {
+ width: 25%;
+ }
+ .col-lg-2 {
+ width: 16.66666667%;
+ }
+ .col-lg-1 {
+ width: 8.33333333%;
+ }
+ .col-lg-pull-12 {
+ right: 100%;
+ }
+ .col-lg-pull-11 {
+ right: 91.66666667%;
+ }
+ .col-lg-pull-10 {
+ right: 83.33333333%;
+ }
+ .col-lg-pull-9 {
+ right: 75%;
+ }
+ .col-lg-pull-8 {
+ right: 66.66666667%;
+ }
+ .col-lg-pull-7 {
+ right: 58.33333333%;
+ }
+ .col-lg-pull-6 {
+ right: 50%;
+ }
+ .col-lg-pull-5 {
+ right: 41.66666667%;
+ }
+ .col-lg-pull-4 {
+ right: 33.33333333%;
+ }
+ .col-lg-pull-3 {
+ right: 25%;
+ }
+ .col-lg-pull-2 {
+ right: 16.66666667%;
+ }
+ .col-lg-pull-1 {
+ right: 8.33333333%;
+ }
+ .col-lg-pull-0 {
+ right: auto;
+ }
+ .col-lg-push-12 {
+ left: 100%;
+ }
+ .col-lg-push-11 {
+ left: 91.66666667%;
+ }
+ .col-lg-push-10 {
+ left: 83.33333333%;
+ }
+ .col-lg-push-9 {
+ left: 75%;
+ }
+ .col-lg-push-8 {
+ left: 66.66666667%;
+ }
+ .col-lg-push-7 {
+ left: 58.33333333%;
+ }
+ .col-lg-push-6 {
+ left: 50%;
+ }
+ .col-lg-push-5 {
+ left: 41.66666667%;
+ }
+ .col-lg-push-4 {
+ left: 33.33333333%;
+ }
+ .col-lg-push-3 {
+ left: 25%;
+ }
+ .col-lg-push-2 {
+ left: 16.66666667%;
+ }
+ .col-lg-push-1 {
+ left: 8.33333333%;
+ }
+ .col-lg-push-0 {
+ left: auto;
+ }
+ .col-lg-offset-12 {
+ margin-left: 100%;
+ }
+ .col-lg-offset-11 {
+ margin-left: 91.66666667%;
+ }
+ .col-lg-offset-10 {
+ margin-left: 83.33333333%;
+ }
+ .col-lg-offset-9 {
+ margin-left: 75%;
+ }
+ .col-lg-offset-8 {
+ margin-left: 66.66666667%;
+ }
+ .col-lg-offset-7 {
+ margin-left: 58.33333333%;
+ }
+ .col-lg-offset-6 {
+ margin-left: 50%;
+ }
+ .col-lg-offset-5 {
+ margin-left: 41.66666667%;
+ }
+ .col-lg-offset-4 {
+ margin-left: 33.33333333%;
+ }
+ .col-lg-offset-3 {
+ margin-left: 25%;
+ }
+ .col-lg-offset-2 {
+ margin-left: 16.66666667%;
+ }
+ .col-lg-offset-1 {
+ margin-left: 8.33333333%;
+ }
+ .col-lg-offset-0 {
+ margin-left: 0;
+ }
+}
+table {
+ background-color: transparent;
+}
+caption {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ color: #777;
+ text-align: left;
+}
+th {
+ text-align: left;
+}
+.table {
+ width: 100%;
+ max-width: 100%;
+ margin-bottom: 20px;
+}
+.table > thead > tr > th,
+.table > tbody > tr > th,
+.table > tfoot > tr > th,
+.table > thead > tr > td,
+.table > tbody > tr > td,
+.table > tfoot > tr > td {
+ padding: 8px;
+ line-height: 1.42857143;
+ vertical-align: top;
+ border-top: 1px solid #ddd;
+}
+.table > thead > tr > th {
+ vertical-align: bottom;
+ border-bottom: 2px solid #ddd;
+}
+.table > caption + thead > tr:first-child > th,
+.table > colgroup + thead > tr:first-child > th,
+.table > thead:first-child > tr:first-child > th,
+.table > caption + thead > tr:first-child > td,
+.table > colgroup + thead > tr:first-child > td,
+.table > thead:first-child > tr:first-child > td {
+ border-top: 0;
+}
+.table > tbody + tbody {
+ border-top: 2px solid #ddd;
+}
+.table .table {
+ background-color: #fff;
+}
+.table-condensed > thead > tr > th,
+.table-condensed > tbody > tr > th,
+.table-condensed > tfoot > tr > th,
+.table-condensed > thead > tr > td,
+.table-condensed > tbody > tr > td,
+.table-condensed > tfoot > tr > td {
+ padding: 5px;
+}
+.table-bordered {
+ border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > tbody > tr > th,
+.table-bordered > tfoot > tr > th,
+.table-bordered > thead > tr > td,
+.table-bordered > tbody > tr > td,
+.table-bordered > tfoot > tr > td {
+ border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > thead > tr > td {
+ border-bottom-width: 2px;
+}
+.table-striped > tbody > tr:nth-child(odd) {
+ background-color: #f9f9f9;
+}
+.table-hover > tbody > tr:hover {
+ background-color: #f5f5f5;
+}
+table col[class*="col-"] {
+ position: static;
+ display: table-column;
+ float: none;
+}
+table td[class*="col-"],
+table th[class*="col-"] {
+ position: static;
+ display: table-cell;
+ float: none;
+}
+.table > thead > tr > td.active,
+.table > tbody > tr > td.active,
+.table > tfoot > tr > td.active,
+.table > thead > tr > th.active,
+.table > tbody > tr > th.active,
+.table > tfoot > tr > th.active,
+.table > thead > tr.active > td,
+.table > tbody > tr.active > td,
+.table > tfoot > tr.active > td,
+.table > thead > tr.active > th,
+.table > tbody > tr.active > th,
+.table > tfoot > tr.active > th {
+ background-color: #f5f5f5;
+}
+.table-hover > tbody > tr > td.active:hover,
+.table-hover > tbody > tr > th.active:hover,
+.table-hover > tbody > tr.active:hover > td,
+.table-hover > tbody > tr:hover > .active,
+.table-hover > tbody > tr.active:hover > th {
+ background-color: #e8e8e8;
+}
+.table > thead > tr > td.success,
+.table > tbody > tr > td.success,
+.table > tfoot > tr > td.success,
+.table > thead > tr > th.success,
+.table > tbody > tr > th.success,
+.table > tfoot > tr > th.success,
+.table > thead > tr.success > td,
+.table > tbody > tr.success > td,
+.table > tfoot > tr.success > td,
+.table > thead > tr.success > th,
+.table > tbody > tr.success > th,
+.table > tfoot > tr.success > th {
+ background-color: #dff0d8;
+}
+.table-hover > tbody > tr > td.success:hover,
+.table-hover > tbody > tr > th.success:hover,
+.table-hover > tbody > tr.success:hover > td,
+.table-hover > tbody > tr:hover > .success,
+.table-hover > tbody > tr.success:hover > th {
+ background-color: #d0e9c6;
+}
+.table > thead > tr > td.info,
+.table > tbody > tr > td.info,
+.table > tfoot > tr > td.info,
+.table > thead > tr > th.info,
+.table > tbody > tr > th.info,
+.table > tfoot > tr > th.info,
+.table > thead > tr.info > td,
+.table > tbody > tr.info > td,
+.table > tfoot > tr.info > td,
+.table > thead > tr.info > th,
+.table > tbody > tr.info > th,
+.table > tfoot > tr.info > th {
+ background-color: #d9edf7;
+}
+.table-hover > tbody > tr > td.info:hover,
+.table-hover > tbody > tr > th.info:hover,
+.table-hover > tbody > tr.info:hover > td,
+.table-hover > tbody > tr:hover > .info,
+.table-hover > tbody > tr.info:hover > th {
+ background-color: #c4e3f3;
+}
+.table > thead > tr > td.warning,
+.table > tbody > tr > td.warning,
+.table > tfoot > tr > td.warning,
+.table > thead > tr > th.warning,
+.table > tbody > tr > th.warning,
+.table > tfoot > tr > th.warning,
+.table > thead > tr.warning > td,
+.table > tbody > tr.warning > td,
+.table > tfoot > tr.warning > td,
+.table > thead > tr.warning > th,
+.table > tbody > tr.warning > th,
+.table > tfoot > tr.warning > th {
+ background-color: #fcf8e3;
+}
+.table-hover > tbody > tr > td.warning:hover,
+.table-hover > tbody > tr > th.warning:hover,
+.table-hover > tbody > tr.warning:hover > td,
+.table-hover > tbody > tr:hover > .warning,
+.table-hover > tbody > tr.warning:hover > th {
+ background-color: #faf2cc;
+}
+.table > thead > tr > td.danger,
+.table > tbody > tr > td.danger,
+.table > tfoot > tr > td.danger,
+.table > thead > tr > th.danger,
+.table > tbody > tr > th.danger,
+.table > tfoot > tr > th.danger,
+.table > thead > tr.danger > td,
+.table > tbody > tr.danger > td,
+.table > tfoot > tr.danger > td,
+.table > thead > tr.danger > th,
+.table > tbody > tr.danger > th,
+.table > tfoot > tr.danger > th {
+ background-color: #f2dede;
+}
+.table-hover > tbody > tr > td.danger:hover,
+.table-hover > tbody > tr > th.danger:hover,
+.table-hover > tbody > tr.danger:hover > td,
+.table-hover > tbody > tr:hover > .danger,
+.table-hover > tbody > tr.danger:hover > th {
+ background-color: #ebcccc;
+}
+.table-responsive {
+ min-height: .01%;
+ overflow-x: auto;
+}
+@media screen and (max-width: 767px) {
+ .table-responsive {
+ width: 100%;
+ margin-bottom: 15px;
+ overflow-y: hidden;
+ -ms-overflow-style: -ms-autohiding-scrollbar;
+ border: 1px solid #ddd;
+ }
+ .table-responsive > .table {
+ margin-bottom: 0;
+ }
+ .table-responsive > .table > thead > tr > th,
+ .table-responsive > .table > tbody > tr > th,
+ .table-responsive > .table > tfoot > tr > th,
+ .table-responsive > .table > thead > tr > td,
+ .table-responsive > .table > tbody > tr > td,
+ .table-responsive > .table > tfoot > tr > td {
+ white-space: nowrap;
+ }
+ .table-responsive > .table-bordered {
+ border: 0;
+ }
+ .table-responsive > .table-bordered > thead > tr > th:first-child,
+ .table-responsive > .table-bordered > tbody > tr > th:first-child,
+ .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+ .table-responsive > .table-bordered > thead > tr > td:first-child,
+ .table-responsive > .table-bordered > tbody > tr > td:first-child,
+ .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+ border-left: 0;
+ }
+ .table-responsive > .table-bordered > thead > tr > th:last-child,
+ .table-responsive > .table-bordered > tbody > tr > th:last-child,
+ .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+ .table-responsive > .table-bordered > thead > tr > td:last-child,
+ .table-responsive > .table-bordered > tbody > tr > td:last-child,
+ .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+ border-right: 0;
+ }
+ .table-responsive > .table-bordered > tbody > tr:last-child > th,
+ .table-responsive > .table-bordered > tfoot > tr:last-child > th,
+ .table-responsive > .table-bordered > tbody > tr:last-child > td,
+ .table-responsive > .table-bordered > tfoot > tr:last-child > td {
+ border-bottom: 0;
+ }
+}
+fieldset {
+ min-width: 0;
+ padding: 0;
+ margin: 0;
+ border: 0;
+}
+legend {
+ display: block;
+ width: 100%;
+ padding: 0;
+ margin-bottom: 20px;
+ font-size: 21px;
+ line-height: inherit;
+ color: #333;
+ border: 0;
+ border-bottom: 1px solid #e5e5e5;
+}
+label {
+ display: inline-block;
+ max-width: 100%;
+ margin-bottom: 5px;
+ font-weight: bold;
+}
+input[type="search"] {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+input[type="radio"],
+input[type="checkbox"] {
+ margin: 4px 0 0;
+ margin-top: 1px \9;
+ line-height: normal;
+}
+input[type="file"] {
+ display: block;
+}
+input[type="range"] {
+ display: block;
+ width: 100%;
+}
+select[multiple],
+select[size] {
+ height: auto;
+}
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+output {
+ display: block;
+ padding-top: 7px;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #555;
+}
+.form-control {
+ display: block;
+ width: 100%;
+ height: 34px;
+ padding: 6px 12px;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #555;
+ background-color: #fff;
+ background-image: none;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
+ -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+ transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+}
+.form-control:focus {
+ border-color: #66afe9;
+ outline: 0;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
+}
+.form-control::-moz-placeholder {
+ color: #999;
+ opacity: 1;
+}
+.form-control:-ms-input-placeholder {
+ color: #999;
+}
+.form-control::-webkit-input-placeholder {
+ color: #999;
+}
+.form-control[disabled],
+.form-control[readonly],
+fieldset[disabled] .form-control {
+ cursor: not-allowed;
+ background-color: #eee;
+ opacity: 1;
+}
+textarea.form-control {
+ height: auto;
+}
+input[type="search"] {
+ -webkit-appearance: none;
+}
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+ input[type="date"],
+ input[type="time"],
+ input[type="datetime-local"],
+ input[type="month"] {
+ line-height: 34px;
+ }
+ input[type="date"].input-sm,
+ input[type="time"].input-sm,
+ input[type="datetime-local"].input-sm,
+ input[type="month"].input-sm {
+ line-height: 30px;
+ }
+ input[type="date"].input-lg,
+ input[type="time"].input-lg,
+ input[type="datetime-local"].input-lg,
+ input[type="month"].input-lg {
+ line-height: 46px;
+ }
+}
+.form-group {
+ margin-bottom: 15px;
+}
+.radio,
+.checkbox {
+ position: relative;
+ display: block;
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+.radio label,
+.checkbox label {
+ min-height: 20px;
+ padding-left: 20px;
+ margin-bottom: 0;
+ font-weight: normal;
+ cursor: pointer;
+}
+.radio input[type="radio"],
+.radio-inline input[type="radio"],
+.checkbox input[type="checkbox"],
+.checkbox-inline input[type="checkbox"] {
+ position: absolute;
+ margin-top: 4px \9;
+ margin-left: -20px;
+}
+.radio + .radio,
+.checkbox + .checkbox {
+ margin-top: -5px;
+}
+.radio-inline,
+.checkbox-inline {
+ display: inline-block;
+ padding-left: 20px;
+ margin-bottom: 0;
+ font-weight: normal;
+ vertical-align: middle;
+ cursor: pointer;
+}
+.radio-inline + .radio-inline,
+.checkbox-inline + .checkbox-inline {
+ margin-top: 0;
+ margin-left: 10px;
+}
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"].disabled,
+input[type="checkbox"].disabled,
+fieldset[disabled] input[type="radio"],
+fieldset[disabled] input[type="checkbox"] {
+ cursor: not-allowed;
+}
+.radio-inline.disabled,
+.checkbox-inline.disabled,
+fieldset[disabled] .radio-inline,
+fieldset[disabled] .checkbox-inline {
+ cursor: not-allowed;
+}
+.radio.disabled label,
+.checkbox.disabled label,
+fieldset[disabled] .radio label,
+fieldset[disabled] .checkbox label {
+ cursor: not-allowed;
+}
+.form-control-static {
+ padding-top: 7px;
+ padding-bottom: 7px;
+ margin-bottom: 0;
+}
+.form-control-static.input-lg,
+.form-control-static.input-sm {
+ padding-right: 0;
+ padding-left: 0;
+}
+.input-sm,
+.form-group-sm .form-control {
+ height: 30px;
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+select.input-sm,
+select.form-group-sm .form-control {
+ height: 30px;
+ line-height: 30px;
+}
+textarea.input-sm,
+textarea.form-group-sm .form-control,
+select[multiple].input-sm,
+select[multiple].form-group-sm .form-control {
+ height: auto;
+}
+.input-lg,
+.form-group-lg .form-control {
+ height: 46px;
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.33;
+ border-radius: 6px;
+}
+select.input-lg,
+select.form-group-lg .form-control {
+ height: 46px;
+ line-height: 46px;
+}
+textarea.input-lg,
+textarea.form-group-lg .form-control,
+select[multiple].input-lg,
+select[multiple].form-group-lg .form-control {
+ height: auto;
+}
+.has-feedback {
+ position: relative;
+}
+.has-feedback .form-control {
+ padding-right: 42.5px;
+}
+.form-control-feedback {
+ position: absolute;
+ top: 0;
+ right: 0;
+ z-index: 2;
+ display: block;
+ width: 34px;
+ height: 34px;
+ line-height: 34px;
+ text-align: center;
+ pointer-events: none;
+}
+.input-lg + .form-control-feedback {
+ width: 46px;
+ height: 46px;
+ line-height: 46px;
+}
+.input-sm + .form-control-feedback {
+ width: 30px;
+ height: 30px;
+ line-height: 30px;
+}
+.has-success .help-block,
+.has-success .control-label,
+.has-success .radio,
+.has-success .checkbox,
+.has-success .radio-inline,
+.has-success .checkbox-inline,
+.has-success.radio label,
+.has-success.checkbox label,
+.has-success.radio-inline label,
+.has-success.checkbox-inline label {
+ color: #3c763d;
+}
+.has-success .form-control {
+ border-color: #3c763d;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-success .form-control:focus {
+ border-color: #2b542c;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
+}
+.has-success .input-group-addon {
+ color: #3c763d;
+ background-color: #dff0d8;
+ border-color: #3c763d;
+}
+.has-success .form-control-feedback {
+ color: #3c763d;
+}
+.has-warning .help-block,
+.has-warning .control-label,
+.has-warning .radio,
+.has-warning .checkbox,
+.has-warning .radio-inline,
+.has-warning .checkbox-inline,
+.has-warning.radio label,
+.has-warning.checkbox label,
+.has-warning.radio-inline label,
+.has-warning.checkbox-inline label {
+ color: #8a6d3b;
+}
+.has-warning .form-control {
+ border-color: #8a6d3b;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-warning .form-control:focus {
+ border-color: #66512c;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
+}
+.has-warning .input-group-addon {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+ border-color: #8a6d3b;
+}
+.has-warning .form-control-feedback {
+ color: #8a6d3b;
+}
+.has-error .help-block,
+.has-error .control-label,
+.has-error .radio,
+.has-error .checkbox,
+.has-error .radio-inline,
+.has-error .checkbox-inline,
+.has-error.radio label,
+.has-error.checkbox label,
+.has-error.radio-inline label,
+.has-error.checkbox-inline label {
+ color: #a94442;
+}
+.has-error .form-control {
+ border-color: #a94442;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-error .form-control:focus {
+ border-color: #843534;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
+}
+.has-error .input-group-addon {
+ color: #a94442;
+ background-color: #f2dede;
+ border-color: #a94442;
+}
+.has-error .form-control-feedback {
+ color: #a94442;
+}
+.has-feedback label ~ .form-control-feedback {
+ top: 25px;
+}
+.has-feedback label.sr-only ~ .form-control-feedback {
+ top: 0;
+}
+.help-block {
+ display: block;
+ margin-top: 5px;
+ margin-bottom: 10px;
+ color: #737373;
+}
+@media (min-width: 768px) {
+ .form-inline .form-group {
+ display: inline-block;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .form-inline .form-control {
+ display: inline-block;
+ width: auto;
+ vertical-align: middle;
+ }
+ .form-inline .form-control-static {
+ display: inline-block;
+ }
+ .form-inline .input-group {
+ display: inline-table;
+ vertical-align: middle;
+ }
+ .form-inline .input-group .input-group-addon,
+ .form-inline .input-group .input-group-btn,
+ .form-inline .input-group .form-control {
+ width: auto;
+ }
+ .form-inline .input-group > .form-control {
+ width: 100%;
+ }
+ .form-inline .control-label {
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .form-inline .radio,
+ .form-inline .checkbox {
+ display: inline-block;
+ margin-top: 0;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .form-inline .radio label,
+ .form-inline .checkbox label {
+ padding-left: 0;
+ }
+ .form-inline .radio input[type="radio"],
+ .form-inline .checkbox input[type="checkbox"] {
+ position: relative;
+ margin-left: 0;
+ }
+ .form-inline .has-feedback .form-control-feedback {
+ top: 0;
+ }
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox,
+.form-horizontal .radio-inline,
+.form-horizontal .checkbox-inline {
+ padding-top: 7px;
+ margin-top: 0;
+ margin-bottom: 0;
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox {
+ min-height: 27px;
+}
+.form-horizontal .form-group {
+ margin-right: -15px;
+ margin-left: -15px;
+}
+@media (min-width: 768px) {
+ .form-horizontal .control-label {
+ padding-top: 7px;
+ margin-bottom: 0;
+ text-align: right;
+ }
+}
+.form-horizontal .has-feedback .form-control-feedback {
+ right: 15px;
+}
+@media (min-width: 768px) {
+ .form-horizontal .form-group-lg .control-label {
+ padding-top: 14.3px;
+ }
+}
+@media (min-width: 768px) {
+ .form-horizontal .form-group-sm .control-label {
+ padding-top: 6px;
+ }
+}
+.btn {
+ display: inline-block;
+ padding: 6px 12px;
+ margin-bottom: 0;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 1.42857143;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ -ms-touch-action: manipulation;
+ touch-action: manipulation;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ background-image: none;
+ border: 1px solid transparent;
+ border-radius: 4px;
+}
+.btn:focus,
+.btn:active:focus,
+.btn.active:focus,
+.btn.focus,
+.btn:active.focus,
+.btn.active.focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+.btn:hover,
+.btn:focus,
+.btn.focus {
+ color: #333;
+ text-decoration: none;
+}
+.btn:active,
+.btn.active {
+ background-image: none;
+ outline: 0;
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn.disabled,
+.btn[disabled],
+fieldset[disabled] .btn {
+ pointer-events: none;
+ cursor: not-allowed;
+ filter: alpha(opacity=65);
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ opacity: .65;
+}
+.btn-default {
+ color: #333;
+ background-color: #fff;
+ border-color: #ccc;
+}
+.btn-default:hover,
+.btn-default:focus,
+.btn-default.focus,
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+ color: #333;
+ background-color: #e6e6e6;
+ border-color: #adadad;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+ background-image: none;
+}
+.btn-default.disabled,
+.btn-default[disabled],
+fieldset[disabled] .btn-default,
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus,
+.btn-default.disabled:active,
+.btn-default[disabled]:active,
+fieldset[disabled] .btn-default:active,
+.btn-default.disabled.active,
+.btn-default[disabled].active,
+fieldset[disabled] .btn-default.active {
+ background-color: #fff;
+ border-color: #ccc;
+}
+.btn-default .badge {
+ color: #fff;
+ background-color: #333;
+}
+.btn-primary {
+ color: #fff;
+ background-color: #337ab7;
+ border-color: #2e6da4;
+}
+.btn-primary:hover,
+.btn-primary:focus,
+.btn-primary.focus,
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+ color: #fff;
+ background-color: #286090;
+ border-color: #204d74;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+ background-image: none;
+}
+.btn-primary.disabled,
+.btn-primary[disabled],
+fieldset[disabled] .btn-primary,
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus,
+.btn-primary.disabled:active,
+.btn-primary[disabled]:active,
+fieldset[disabled] .btn-primary:active,
+.btn-primary.disabled.active,
+.btn-primary[disabled].active,
+fieldset[disabled] .btn-primary.active {
+ background-color: #337ab7;
+ border-color: #2e6da4;
+}
+.btn-primary .badge {
+ color: #337ab7;
+ background-color: #fff;
+}
+.btn-success {
+ color: #fff;
+ background-color: #5cb85c;
+ border-color: #4cae4c;
+}
+.btn-success:hover,
+.btn-success:focus,
+.btn-success.focus,
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+ color: #fff;
+ background-color: #449d44;
+ border-color: #398439;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+ background-image: none;
+}
+.btn-success.disabled,
+.btn-success[disabled],
+fieldset[disabled] .btn-success,
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus,
+.btn-success.disabled:active,
+.btn-success[disabled]:active,
+fieldset[disabled] .btn-success:active,
+.btn-success.disabled.active,
+.btn-success[disabled].active,
+fieldset[disabled] .btn-success.active {
+ background-color: #5cb85c;
+ border-color: #4cae4c;
+}
+.btn-success .badge {
+ color: #5cb85c;
+ background-color: #fff;
+}
+.btn-info {
+ color: #fff;
+ background-color: #5bc0de;
+ border-color: #46b8da;
+}
+.btn-info:hover,
+.btn-info:focus,
+.btn-info.focus,
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+ color: #fff;
+ background-color: #31b0d5;
+ border-color: #269abc;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+ background-image: none;
+}
+.btn-info.disabled,
+.btn-info[disabled],
+fieldset[disabled] .btn-info,
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus,
+.btn-info.disabled:active,
+.btn-info[disabled]:active,
+fieldset[disabled] .btn-info:active,
+.btn-info.disabled.active,
+.btn-info[disabled].active,
+fieldset[disabled] .btn-info.active {
+ background-color: #5bc0de;
+ border-color: #46b8da;
+}
+.btn-info .badge {
+ color: #5bc0de;
+ background-color: #fff;
+}
+.btn-warning {
+ color: #fff;
+ background-color: #f0ad4e;
+ border-color: #eea236;
+}
+.btn-warning:hover,
+.btn-warning:focus,
+.btn-warning.focus,
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+ color: #fff;
+ background-color: #ec971f;
+ border-color: #d58512;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+ background-image: none;
+}
+.btn-warning.disabled,
+.btn-warning[disabled],
+fieldset[disabled] .btn-warning,
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus,
+.btn-warning.disabled:active,
+.btn-warning[disabled]:active,
+fieldset[disabled] .btn-warning:active,
+.btn-warning.disabled.active,
+.btn-warning[disabled].active,
+fieldset[disabled] .btn-warning.active {
+ background-color: #f0ad4e;
+ border-color: #eea236;
+}
+.btn-warning .badge {
+ color: #f0ad4e;
+ background-color: #fff;
+}
+.btn-danger {
+ color: #fff;
+ background-color: #d9534f;
+ border-color: #d43f3a;
+}
+.btn-danger:hover,
+.btn-danger:focus,
+.btn-danger.focus,
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+ color: #fff;
+ background-color: #c9302c;
+ border-color: #ac2925;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+ background-image: none;
+}
+.btn-danger.disabled,
+.btn-danger[disabled],
+fieldset[disabled] .btn-danger,
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus,
+.btn-danger.disabled:active,
+.btn-danger[disabled]:active,
+fieldset[disabled] .btn-danger:active,
+.btn-danger.disabled.active,
+.btn-danger[disabled].active,
+fieldset[disabled] .btn-danger.active {
+ background-color: #d9534f;
+ border-color: #d43f3a;
+}
+.btn-danger .badge {
+ color: #d9534f;
+ background-color: #fff;
+}
+.btn-link {
+ font-weight: normal;
+ color: #337ab7;
+ border-radius: 0;
+}
+.btn-link,
+.btn-link:active,
+.btn-link.active,
+.btn-link[disabled],
+fieldset[disabled] .btn-link {
+ background-color: transparent;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.btn-link,
+.btn-link:hover,
+.btn-link:focus,
+.btn-link:active {
+ border-color: transparent;
+}
+.btn-link:hover,
+.btn-link:focus {
+ color: #23527c;
+ text-decoration: underline;
+ background-color: transparent;
+}
+.btn-link[disabled]:hover,
+fieldset[disabled] .btn-link:hover,
+.btn-link[disabled]:focus,
+fieldset[disabled] .btn-link:focus {
+ color: #777;
+ text-decoration: none;
+}
+.btn-lg,
+.btn-group-lg > .btn {
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.33;
+ border-radius: 6px;
+}
+.btn-sm,
+.btn-group-sm > .btn {
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+.btn-xs,
+.btn-group-xs > .btn {
+ padding: 1px 5px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+.btn-block {
+ display: block;
+ width: 100%;
+}
+.btn-block + .btn-block {
+ margin-top: 5px;
+}
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+ width: 100%;
+}
+.fade {
+ opacity: 0;
+ -webkit-transition: opacity .15s linear;
+ -o-transition: opacity .15s linear;
+ transition: opacity .15s linear;
+}
+.fade.in {
+ opacity: 1;
+}
+.collapse {
+ display: none;
+ visibility: hidden;
+}
+.collapse.in {
+ display: block;
+ visibility: visible;
+}
+tr.collapse.in {
+ display: table-row;
+}
+tbody.collapse.in {
+ display: table-row-group;
+}
+.collapsing {
+ position: relative;
+ height: 0;
+ overflow: hidden;
+ -webkit-transition-timing-function: ease;
+ -o-transition-timing-function: ease;
+ transition-timing-function: ease;
+ -webkit-transition-duration: .35s;
+ -o-transition-duration: .35s;
+ transition-duration: .35s;
+ -webkit-transition-property: height, visibility;
+ -o-transition-property: height, visibility;
+ transition-property: height, visibility;
+}
+.caret {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ margin-left: 2px;
+ vertical-align: middle;
+ border-top: 4px solid;
+ border-right: 4px solid transparent;
+ border-left: 4px solid transparent;
+}
+.dropdown {
+ position: relative;
+}
+.dropdown-toggle:focus {
+ outline: 0;
+}
+.dropdown-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: 1000;
+ display: none;
+ float: left;
+ min-width: 160px;
+ padding: 5px 0;
+ margin: 2px 0 0;
+ font-size: 14px;
+ text-align: left;
+ list-style: none;
+ background-color: #fff;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, .15);
+ border-radius: 4px;
+ -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+}
+.dropdown-menu.pull-right {
+ right: 0;
+ left: auto;
+}
+.dropdown-menu .divider {
+ height: 1px;
+ margin: 9px 0;
+ overflow: hidden;
+ background-color: #e5e5e5;
+}
+.dropdown-menu > li > a {
+ display: block;
+ padding: 3px 20px;
+ clear: both;
+ font-weight: normal;
+ line-height: 1.42857143;
+ color: #333;
+ white-space: nowrap;
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+ color: #262626;
+ text-decoration: none;
+ background-color: #f5f5f5;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ color: #fff;
+ text-decoration: none;
+ background-color: #337ab7;
+ outline: 0;
+}
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ color: #777;
+}
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ text-decoration: none;
+ cursor: not-allowed;
+ background-color: transparent;
+ background-image: none;
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+.open > .dropdown-menu {
+ display: block;
+}
+.open > a {
+ outline: 0;
+}
+.dropdown-menu-right {
+ right: 0;
+ left: auto;
+}
+.dropdown-menu-left {
+ right: auto;
+ left: 0;
+}
+.dropdown-header {
+ display: block;
+ padding: 3px 20px;
+ font-size: 12px;
+ line-height: 1.42857143;
+ color: #777;
+ white-space: nowrap;
+}
+.dropdown-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 990;
+}
+.pull-right > .dropdown-menu {
+ right: 0;
+ left: auto;
+}
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+ content: "";
+ border-top: 0;
+ border-bottom: 4px solid;
+}
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+ top: auto;
+ bottom: 100%;
+ margin-bottom: 1px;
+}
+@media (min-width: 768px) {
+ .navbar-right .dropdown-menu {
+ right: 0;
+ left: auto;
+ }
+ .navbar-right .dropdown-menu-left {
+ right: auto;
+ left: 0;
+ }
+}
+.btn-group,
+.btn-group-vertical {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+}
+.btn-group > .btn,
+.btn-group-vertical > .btn {
+ position: relative;
+ float: left;
+}
+.btn-group > .btn:hover,
+.btn-group-vertical > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group-vertical > .btn:focus,
+.btn-group > .btn:active,
+.btn-group-vertical > .btn:active,
+.btn-group > .btn.active,
+.btn-group-vertical > .btn.active {
+ z-index: 2;
+}
+.btn-group .btn + .btn,
+.btn-group .btn + .btn-group,
+.btn-group .btn-group + .btn,
+.btn-group .btn-group + .btn-group {
+ margin-left: -1px;
+}
+.btn-toolbar {
+ margin-left: -5px;
+}
+.btn-toolbar .btn-group,
+.btn-toolbar .input-group {
+ float: left;
+}
+.btn-toolbar > .btn,
+.btn-toolbar > .btn-group,
+.btn-toolbar > .input-group {
+ margin-left: 5px;
+}
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+ border-radius: 0;
+}
+.btn-group > .btn:first-child {
+ margin-left: 0;
+}
+.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group > .btn-group {
+ float: left;
+}
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+ border-radius: 0;
+}
+.btn-group > .btn-group:first-child > .btn:last-child,
+.btn-group > .btn-group:first-child > .dropdown-toggle {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.btn-group > .btn-group:last-child > .btn:first-child {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+ outline: 0;
+}
+.btn-group > .btn + .dropdown-toggle {
+ padding-right: 8px;
+ padding-left: 8px;
+}
+.btn-group > .btn-lg + .dropdown-toggle {
+ padding-right: 12px;
+ padding-left: 12px;
+}
+.btn-group.open .dropdown-toggle {
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn-group.open .dropdown-toggle.btn-link {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.btn .caret {
+ margin-left: 0;
+}
+.btn-lg .caret {
+ border-width: 5px 5px 0;
+ border-bottom-width: 0;
+}
+.dropup .btn-lg .caret {
+ border-width: 0 5px 5px;
+}
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group,
+.btn-group-vertical > .btn-group > .btn {
+ display: block;
+ float: none;
+ width: 100%;
+ max-width: 100%;
+}
+.btn-group-vertical > .btn-group > .btn {
+ float: none;
+}
+.btn-group-vertical > .btn + .btn,
+.btn-group-vertical > .btn + .btn-group,
+.btn-group-vertical > .btn-group + .btn,
+.btn-group-vertical > .btn-group + .btn-group {
+ margin-top: -1px;
+ margin-left: 0;
+}
+.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
+ border-radius: 0;
+}
+.btn-group-vertical > .btn:first-child:not(:last-child) {
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn:last-child:not(:first-child) {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-left-radius: 4px;
+}
+.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
+ border-radius: 0;
+}
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+.btn-group-justified {
+ display: table;
+ width: 100%;
+ table-layout: fixed;
+ border-collapse: separate;
+}
+.btn-group-justified > .btn,
+.btn-group-justified > .btn-group {
+ display: table-cell;
+ float: none;
+ width: 1%;
+}
+.btn-group-justified > .btn-group .btn {
+ width: 100%;
+}
+.btn-group-justified > .btn-group .dropdown-menu {
+ left: auto;
+}
+[data-toggle="buttons"] > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn input[type="checkbox"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
+ position: absolute;
+ clip: rect(0, 0, 0, 0);
+ pointer-events: none;
+}
+.input-group {
+ position: relative;
+ display: table;
+ border-collapse: separate;
+}
+.input-group[class*="col-"] {
+ float: none;
+ padding-right: 0;
+ padding-left: 0;
+}
+.input-group .form-control {
+ position: relative;
+ z-index: 2;
+ float: left;
+ width: 100%;
+ margin-bottom: 0;
+}
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn {
+ height: 46px;
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.33;
+ border-radius: 6px;
+}
+select.input-group-lg > .form-control,
+select.input-group-lg > .input-group-addon,
+select.input-group-lg > .input-group-btn > .btn {
+ height: 46px;
+ line-height: 46px;
+}
+textarea.input-group-lg > .form-control,
+textarea.input-group-lg > .input-group-addon,
+textarea.input-group-lg > .input-group-btn > .btn,
+select[multiple].input-group-lg > .form-control,
+select[multiple].input-group-lg > .input-group-addon,
+select[multiple].input-group-lg > .input-group-btn > .btn {
+ height: auto;
+}
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn {
+ height: 30px;
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+select.input-group-sm > .form-control,
+select.input-group-sm > .input-group-addon,
+select.input-group-sm > .input-group-btn > .btn {
+ height: 30px;
+ line-height: 30px;
+}
+textarea.input-group-sm > .form-control,
+textarea.input-group-sm > .input-group-addon,
+textarea.input-group-sm > .input-group-btn > .btn,
+select[multiple].input-group-sm > .form-control,
+select[multiple].input-group-sm > .input-group-addon,
+select[multiple].input-group-sm > .input-group-btn > .btn {
+ height: auto;
+}
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+ display: table-cell;
+}
+.input-group-addon:not(:first-child):not(:last-child),
+.input-group-btn:not(:first-child):not(:last-child),
+.input-group .form-control:not(:first-child):not(:last-child) {
+ border-radius: 0;
+}
+.input-group-addon,
+.input-group-btn {
+ width: 1%;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+.input-group-addon {
+ padding: 6px 12px;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 1;
+ color: #555;
+ text-align: center;
+ background-color: #eee;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+}
+.input-group-addon.input-sm {
+ padding: 5px 10px;
+ font-size: 12px;
+ border-radius: 3px;
+}
+.input-group-addon.input-lg {
+ padding: 10px 16px;
+ font-size: 18px;
+ border-radius: 6px;
+}
+.input-group-addon input[type="radio"],
+.input-group-addon input[type="checkbox"] {
+ margin-top: 0;
+}
+.input-group .form-control:first-child,
+.input-group-addon:first-child,
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group > .btn,
+.input-group-btn:first-child > .dropdown-toggle,
+.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.input-group-addon:first-child {
+ border-right: 0;
+}
+.input-group .form-control:last-child,
+.input-group-addon:last-child,
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group > .btn,
+.input-group-btn:last-child > .dropdown-toggle,
+.input-group-btn:first-child > .btn:not(:first-child),
+.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.input-group-addon:last-child {
+ border-left: 0;
+}
+.input-group-btn {
+ position: relative;
+ font-size: 0;
+ white-space: nowrap;
+}
+.input-group-btn > .btn {
+ position: relative;
+}
+.input-group-btn > .btn + .btn {
+ margin-left: -1px;
+}
+.input-group-btn > .btn:hover,
+.input-group-btn > .btn:focus,
+.input-group-btn > .btn:active {
+ z-index: 2;
+}
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group {
+ margin-right: -1px;
+}
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group {
+ margin-left: -1px;
+}
+.nav {
+ padding-left: 0;
+ margin-bottom: 0;
+ list-style: none;
+}
+.nav > li {
+ position: relative;
+ display: block;
+}
+.nav > li > a {
+ position: relative;
+ display: block;
+ padding: 10px 15px;
+}
+.nav > li > a:hover,
+.nav > li > a:focus {
+ text-decoration: none;
+ background-color: #eee;
+}
+.nav > li.disabled > a {
+ color: #777;
+}
+.nav > li.disabled > a:hover,
+.nav > li.disabled > a:focus {
+ color: #777;
+ text-decoration: none;
+ cursor: not-allowed;
+ background-color: transparent;
+}
+.nav .open > a,
+.nav .open > a:hover,
+.nav .open > a:focus {
+ background-color: #eee;
+ border-color: #337ab7;
+}
+.nav .nav-divider {
+ height: 1px;
+ margin: 9px 0;
+ overflow: hidden;
+ background-color: #e5e5e5;
+}
+.nav > li > a > img {
+ max-width: none;
+}
+.nav-tabs {
+ border-bottom: 1px solid #ddd;
+}
+.nav-tabs > li {
+ float: left;
+ margin-bottom: -1px;
+}
+.nav-tabs > li > a {
+ margin-right: 2px;
+ line-height: 1.42857143;
+ border: 1px solid transparent;
+ border-radius: 4px 4px 0 0;
+}
+.nav-tabs > li > a:hover {
+ border-color: #eee #eee #ddd;
+}
+.nav-tabs > li.active > a,
+.nav-tabs > li.active > a:hover,
+.nav-tabs > li.active > a:focus {
+ color: #555;
+ cursor: default;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ border-bottom-color: transparent;
+}
+.nav-tabs.nav-justified {
+ width: 100%;
+ border-bottom: 0;
+}
+.nav-tabs.nav-justified > li {
+ float: none;
+}
+.nav-tabs.nav-justified > li > a {
+ margin-bottom: 5px;
+ text-align: center;
+}
+.nav-tabs.nav-justified > .dropdown .dropdown-menu {
+ top: auto;
+ left: auto;
+}
+@media (min-width: 768px) {
+ .nav-tabs.nav-justified > li {
+ display: table-cell;
+ width: 1%;
+ }
+ .nav-tabs.nav-justified > li > a {
+ margin-bottom: 0;
+ }
+}
+.nav-tabs.nav-justified > li > a {
+ margin-right: 0;
+ border-radius: 4px;
+}
+.nav-tabs.nav-justified > .active > a,
+.nav-tabs.nav-justified > .active > a:hover,
+.nav-tabs.nav-justified > .active > a:focus {
+ border: 1px solid #ddd;
+}
+@media (min-width: 768px) {
+ .nav-tabs.nav-justified > li > a {
+ border-bottom: 1px solid #ddd;
+ border-radius: 4px 4px 0 0;
+ }
+ .nav-tabs.nav-justified > .active > a,
+ .nav-tabs.nav-justified > .active > a:hover,
+ .nav-tabs.nav-justified > .active > a:focus {
+ border-bottom-color: #fff;
+ }
+}
+.nav-pills > li {
+ float: left;
+}
+.nav-pills > li > a {
+ border-radius: 4px;
+}
+.nav-pills > li + li {
+ margin-left: 2px;
+}
+.nav-pills > li.active > a,
+.nav-pills > li.active > a:hover,
+.nav-pills > li.active > a:focus {
+ color: #fff;
+ background-color: #337ab7;
+}
+.nav-stacked > li {
+ float: none;
+}
+.nav-stacked > li + li {
+ margin-top: 2px;
+ margin-left: 0;
+}
+.nav-justified {
+ width: 100%;
+}
+.nav-justified > li {
+ float: none;
+}
+.nav-justified > li > a {
+ margin-bottom: 5px;
+ text-align: center;
+}
+.nav-justified > .dropdown .dropdown-menu {
+ top: auto;
+ left: auto;
+}
+@media (min-width: 768px) {
+ .nav-justified > li {
+ display: table-cell;
+ width: 1%;
+ }
+ .nav-justified > li > a {
+ margin-bottom: 0;
+ }
+}
+.nav-tabs-justified {
+ border-bottom: 0;
+}
+.nav-tabs-justified > li > a {
+ margin-right: 0;
+ border-radius: 4px;
+}
+.nav-tabs-justified > .active > a,
+.nav-tabs-justified > .active > a:hover,
+.nav-tabs-justified > .active > a:focus {
+ border: 1px solid #ddd;
+}
+@media (min-width: 768px) {
+ .nav-tabs-justified > li > a {
+ border-bottom: 1px solid #ddd;
+ border-radius: 4px 4px 0 0;
+ }
+ .nav-tabs-justified > .active > a,
+ .nav-tabs-justified > .active > a:hover,
+ .nav-tabs-justified > .active > a:focus {
+ border-bottom-color: #fff;
+ }
+}
+.tab-content > .tab-pane {
+ display: none;
+ visibility: hidden;
+}
+.tab-content > .active {
+ display: block;
+ visibility: visible;
+}
+.nav-tabs .dropdown-menu {
+ margin-top: -1px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+.navbar {
+ position: relative;
+ min-height: 50px;
+ margin-bottom: 20px;
+ border: 1px solid transparent;
+}
+@media (min-width: 768px) {
+ .navbar {
+ border-radius: 4px;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-header {
+ float: left;
+ }
+}
+.navbar-collapse {
+ padding-right: 15px;
+ padding-left: 15px;
+ overflow-x: visible;
+ -webkit-overflow-scrolling: touch;
+ border-top: 1px solid transparent;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
+}
+.navbar-collapse.in {
+ overflow-y: auto;
+}
+@media (min-width: 768px) {
+ .navbar-collapse {
+ width: auto;
+ border-top: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+ .navbar-collapse.collapse {
+ display: block !important;
+ height: auto !important;
+ padding-bottom: 0;
+ overflow: visible !important;
+ visibility: visible !important;
+ }
+ .navbar-collapse.in {
+ overflow-y: visible;
+ }
+ .navbar-fixed-top .navbar-collapse,
+ .navbar-static-top .navbar-collapse,
+ .navbar-fixed-bottom .navbar-collapse {
+ padding-right: 0;
+ padding-left: 0;
+ }
+}
+.navbar-fixed-top .navbar-collapse,
+.navbar-fixed-bottom .navbar-collapse {
+ max-height: 340px;
+}
+@media (max-device-width: 480px) and (orientation: landscape) {
+ .navbar-fixed-top .navbar-collapse,
+ .navbar-fixed-bottom .navbar-collapse {
+ max-height: 200px;
+ }
+}
+.container > .navbar-header,
+.container-fluid > .navbar-header,
+.container > .navbar-collapse,
+.container-fluid > .navbar-collapse {
+ margin-right: -15px;
+ margin-left: -15px;
+}
+@media (min-width: 768px) {
+ .container > .navbar-header,
+ .container-fluid > .navbar-header,
+ .container > .navbar-collapse,
+ .container-fluid > .navbar-collapse {
+ margin-right: 0;
+ margin-left: 0;
+ }
+}
+.navbar-static-top {
+ z-index: 1000;
+ border-width: 0 0 1px;
+}
+@media (min-width: 768px) {
+ .navbar-static-top {
+ border-radius: 0;
+ }
+}
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ position: fixed;
+ right: 0;
+ left: 0;
+ z-index: 1030;
+}
+@media (min-width: 768px) {
+ .navbar-fixed-top,
+ .navbar-fixed-bottom {
+ border-radius: 0;
+ }
+}
+.navbar-fixed-top {
+ top: 0;
+ border-width: 0 0 1px;
+}
+.navbar-fixed-bottom {
+ bottom: 0;
+ margin-bottom: 0;
+ border-width: 1px 0 0;
+}
+.navbar-brand {
+ float: left;
+ height: 50px;
+ padding: 15px 15px;
+ font-size: 18px;
+ line-height: 20px;
+}
+.navbar-brand:hover,
+.navbar-brand:focus {
+ text-decoration: none;
+}
+.navbar-brand > img {
+ display: block;
+}
+@media (min-width: 768px) {
+ .navbar > .container .navbar-brand,
+ .navbar > .container-fluid .navbar-brand {
+ margin-left: -15px;
+ }
+}
+.navbar-toggle {
+ position: relative;
+ float: right;
+ padding: 9px 10px;
+ margin-top: 8px;
+ margin-right: 15px;
+ margin-bottom: 8px;
+ background-color: transparent;
+ background-image: none;
+ border: 1px solid transparent;
+ border-radius: 4px;
+}
+.navbar-toggle:focus {
+ outline: 0;
+}
+.navbar-toggle .icon-bar {
+ display: block;
+ width: 22px;
+ height: 2px;
+ border-radius: 1px;
+}
+.navbar-toggle .icon-bar + .icon-bar {
+ margin-top: 4px;
+}
+@media (min-width: 768px) {
+ .navbar-toggle {
+ display: none;
+ }
+}
+.navbar-nav {
+ margin: 7.5px -15px;
+}
+.navbar-nav > li > a {
+ padding-top: 10px;
+ padding-bottom: 10px;
+ line-height: 20px;
+}
+@media (max-width: 767px) {
+ .navbar-nav .open .dropdown-menu {
+ position: static;
+ float: none;
+ width: auto;
+ margin-top: 0;
+ background-color: transparent;
+ border: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+ .navbar-nav .open .dropdown-menu > li > a,
+ .navbar-nav .open .dropdown-menu .dropdown-header {
+ padding: 5px 15px 5px 25px;
+ }
+ .navbar-nav .open .dropdown-menu > li > a {
+ line-height: 20px;
+ }
+ .navbar-nav .open .dropdown-menu > li > a:hover,
+ .navbar-nav .open .dropdown-menu > li > a:focus {
+ background-image: none;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-nav {
+ float: left;
+ margin: 0;
+ }
+ .navbar-nav > li {
+ float: left;
+ }
+ .navbar-nav > li > a {
+ padding-top: 15px;
+ padding-bottom: 15px;
+ }
+}
+.navbar-form {
+ padding: 10px 15px;
+ margin-top: 8px;
+ margin-right: -15px;
+ margin-bottom: 8px;
+ margin-left: -15px;
+ border-top: 1px solid transparent;
+ border-bottom: 1px solid transparent;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
+}
+@media (min-width: 768px) {
+ .navbar-form .form-group {
+ display: inline-block;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .navbar-form .form-control {
+ display: inline-block;
+ width: auto;
+ vertical-align: middle;
+ }
+ .navbar-form .form-control-static {
+ display: inline-block;
+ }
+ .navbar-form .input-group {
+ display: inline-table;
+ vertical-align: middle;
+ }
+ .navbar-form .input-group .input-group-addon,
+ .navbar-form .input-group .input-group-btn,
+ .navbar-form .input-group .form-control {
+ width: auto;
+ }
+ .navbar-form .input-group > .form-control {
+ width: 100%;
+ }
+ .navbar-form .control-label {
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .navbar-form .radio,
+ .navbar-form .checkbox {
+ display: inline-block;
+ margin-top: 0;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .navbar-form .radio label,
+ .navbar-form .checkbox label {
+ padding-left: 0;
+ }
+ .navbar-form .radio input[type="radio"],
+ .navbar-form .checkbox input[type="checkbox"] {
+ position: relative;
+ margin-left: 0;
+ }
+ .navbar-form .has-feedback .form-control-feedback {
+ top: 0;
+ }
+}
+@media (max-width: 767px) {
+ .navbar-form .form-group {
+ margin-bottom: 5px;
+ }
+ .navbar-form .form-group:last-child {
+ margin-bottom: 0;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-form {
+ width: auto;
+ padding-top: 0;
+ padding-bottom: 0;
+ margin-right: 0;
+ margin-left: 0;
+ border: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+}
+.navbar-nav > li > .dropdown-menu {
+ margin-top: 0;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.navbar-btn {
+ margin-top: 8px;
+ margin-bottom: 8px;
+}
+.navbar-btn.btn-sm {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+.navbar-btn.btn-xs {
+ margin-top: 14px;
+ margin-bottom: 14px;
+}
+.navbar-text {
+ margin-top: 15px;
+ margin-bottom: 15px;
+}
+@media (min-width: 768px) {
+ .navbar-text {
+ float: left;
+ margin-right: 15px;
+ margin-left: 15px;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-left {
+ float: left !important;
+ }
+ .navbar-right {
+ float: right !important;
+ margin-right: -15px;
+ }
+ .navbar-right ~ .navbar-right {
+ margin-right: 0;
+ }
+}
+.navbar-default {
+ background-color: #f8f8f8;
+ border-color: #e7e7e7;
+}
+.navbar-default .navbar-brand {
+ color: #777;
+}
+.navbar-default .navbar-brand:hover,
+.navbar-default .navbar-brand:focus {
+ color: #5e5e5e;
+ background-color: transparent;
+}
+.navbar-default .navbar-text {
+ color: #777;
+}
+.navbar-default .navbar-nav > li > a {
+ color: #777;
+}
+.navbar-default .navbar-nav > li > a:hover,
+.navbar-default .navbar-nav > li > a:focus {
+ color: #333;
+ background-color: transparent;
+}
+.navbar-default .navbar-nav > .active > a,
+.navbar-default .navbar-nav > .active > a:hover,
+.navbar-default .navbar-nav > .active > a:focus {
+ color: #555;
+ background-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .disabled > a,
+.navbar-default .navbar-nav > .disabled > a:hover,
+.navbar-default .navbar-nav > .disabled > a:focus {
+ color: #ccc;
+ background-color: transparent;
+}
+.navbar-default .navbar-toggle {
+ border-color: #ddd;
+}
+.navbar-default .navbar-toggle:hover,
+.navbar-default .navbar-toggle:focus {
+ background-color: #ddd;
+}
+.navbar-default .navbar-toggle .icon-bar {
+ background-color: #888;
+}
+.navbar-default .navbar-collapse,
+.navbar-default .navbar-form {
+ border-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .open > a:hover,
+.navbar-default .navbar-nav > .open > a:focus {
+ color: #555;
+ background-color: #e7e7e7;
+}
+@media (max-width: 767px) {
+ .navbar-default .navbar-nav .open .dropdown-menu > li > a {
+ color: #777;
+ }
+ .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
+ .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
+ color: #333;
+ background-color: transparent;
+ }
+ .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
+ .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
+ .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
+ color: #555;
+ background-color: #e7e7e7;
+ }
+ .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
+ .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+ .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+ color: #ccc;
+ background-color: transparent;
+ }
+}
+.navbar-default .navbar-link {
+ color: #777;
+}
+.navbar-default .navbar-link:hover {
+ color: #333;
+}
+.navbar-default .btn-link {
+ color: #777;
+}
+.navbar-default .btn-link:hover,
+.navbar-default .btn-link:focus {
+ color: #333;
+}
+.navbar-default .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-default .btn-link:hover,
+.navbar-default .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-default .btn-link:focus {
+ color: #ccc;
+}
+.navbar-inverse {
+ background-color: #222;
+ border-color: #080808;
+}
+.navbar-inverse .navbar-brand {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-brand:hover,
+.navbar-inverse .navbar-brand:focus {
+ color: #fff;
+ background-color: transparent;
+}
+.navbar-inverse .navbar-text {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a:hover,
+.navbar-inverse .navbar-nav > li > a:focus {
+ color: #fff;
+ background-color: transparent;
+}
+.navbar-inverse .navbar-nav > .active > a,
+.navbar-inverse .navbar-nav > .active > a:hover,
+.navbar-inverse .navbar-nav > .active > a:focus {
+ color: #fff;
+ background-color: #080808;
+}
+.navbar-inverse .navbar-nav > .disabled > a,
+.navbar-inverse .navbar-nav > .disabled > a:hover,
+.navbar-inverse .navbar-nav > .disabled > a:focus {
+ color: #444;
+ background-color: transparent;
+}
+.navbar-inverse .navbar-toggle {
+ border-color: #333;
+}
+.navbar-inverse .navbar-toggle:hover,
+.navbar-inverse .navbar-toggle:focus {
+ background-color: #333;
+}
+.navbar-inverse .navbar-toggle .icon-bar {
+ background-color: #fff;
+}
+.navbar-inverse .navbar-collapse,
+.navbar-inverse .navbar-form {
+ border-color: #101010;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .open > a:hover,
+.navbar-inverse .navbar-nav > .open > a:focus {
+ color: #fff;
+ background-color: #080808;
+}
+@media (max-width: 767px) {
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
+ border-color: #080808;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
+ background-color: #080808;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
+ color: #9d9d9d;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
+ color: #fff;
+ background-color: transparent;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
+ color: #fff;
+ background-color: #080808;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+ color: #444;
+ background-color: transparent;
+ }
+}
+.navbar-inverse .navbar-link {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-link:hover {
+ color: #fff;
+}
+.navbar-inverse .btn-link {
+ color: #9d9d9d;
+}
+.navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link:focus {
+ color: #fff;
+}
+.navbar-inverse .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-inverse .btn-link:focus {
+ color: #444;
+}
+.breadcrumb {
+ padding: 8px 15px;
+ margin-bottom: 20px;
+ list-style: none;
+ background-color: #f5f5f5;
+ border-radius: 4px;
+}
+.breadcrumb > li {
+ display: inline-block;
+}
+.breadcrumb > li + li:before {
+ padding: 0 5px;
+ color: #ccc;
+ content: "/\00a0";
+}
+.breadcrumb > .active {
+ color: #777;
+}
+.pagination {
+ display: inline-block;
+ padding-left: 0;
+ margin: 20px 0;
+ border-radius: 4px;
+}
+.pagination > li {
+ display: inline;
+}
+.pagination > li > a,
+.pagination > li > span {
+ position: relative;
+ float: left;
+ padding: 6px 12px;
+ margin-left: -1px;
+ line-height: 1.42857143;
+ color: #337ab7;
+ text-decoration: none;
+ background-color: #fff;
+ border: 1px solid #ddd;
+}
+.pagination > li:first-child > a,
+.pagination > li:first-child > span {
+ margin-left: 0;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+.pagination > li:last-child > a,
+.pagination > li:last-child > span {
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+}
+.pagination > li > a:hover,
+.pagination > li > span:hover,
+.pagination > li > a:focus,
+.pagination > li > span:focus {
+ color: #23527c;
+ background-color: #eee;
+ border-color: #ddd;
+}
+.pagination > .active > a,
+.pagination > .active > span,
+.pagination > .active > a:hover,
+.pagination > .active > span:hover,
+.pagination > .active > a:focus,
+.pagination > .active > span:focus {
+ z-index: 2;
+ color: #fff;
+ cursor: default;
+ background-color: #337ab7;
+ border-color: #337ab7;
+}
+.pagination > .disabled > span,
+.pagination > .disabled > span:hover,
+.pagination > .disabled > span:focus,
+.pagination > .disabled > a,
+.pagination > .disabled > a:hover,
+.pagination > .disabled > a:focus {
+ color: #777;
+ cursor: not-allowed;
+ background-color: #fff;
+ border-color: #ddd;
+}
+.pagination-lg > li > a,
+.pagination-lg > li > span {
+ padding: 10px 16px;
+ font-size: 18px;
+}
+.pagination-lg > li:first-child > a,
+.pagination-lg > li:first-child > span {
+ border-top-left-radius: 6px;
+ border-bottom-left-radius: 6px;
+}
+.pagination-lg > li:last-child > a,
+.pagination-lg > li:last-child > span {
+ border-top-right-radius: 6px;
+ border-bottom-right-radius: 6px;
+}
+.pagination-sm > li > a,
+.pagination-sm > li > span {
+ padding: 5px 10px;
+ font-size: 12px;
+}
+.pagination-sm > li:first-child > a,
+.pagination-sm > li:first-child > span {
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.pagination-sm > li:last-child > a,
+.pagination-sm > li:last-child > span {
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+.pager {
+ padding-left: 0;
+ margin: 20px 0;
+ text-align: center;
+ list-style: none;
+}
+.pager li {
+ display: inline;
+}
+.pager li > a,
+.pager li > span {
+ display: inline-block;
+ padding: 5px 14px;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ border-radius: 15px;
+}
+.pager li > a:hover,
+.pager li > a:focus {
+ text-decoration: none;
+ background-color: #eee;
+}
+.pager .next > a,
+.pager .next > span {
+ float: right;
+}
+.pager .previous > a,
+.pager .previous > span {
+ float: left;
+}
+.pager .disabled > a,
+.pager .disabled > a:hover,
+.pager .disabled > a:focus,
+.pager .disabled > span {
+ color: #777;
+ cursor: not-allowed;
+ background-color: #fff;
+}
+.label {
+ display: inline;
+ padding: .2em .6em .3em;
+ font-size: 75%;
+ font-weight: bold;
+ line-height: 1;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ border-radius: .25em;
+}
+a.label:hover,
+a.label:focus {
+ color: #fff;
+ text-decoration: none;
+ cursor: pointer;
+}
+.label:empty {
+ display: none;
+}
+.btn .label {
+ position: relative;
+ top: -1px;
+}
+.label-default {
+ background-color: #777;
+}
+.label-default[href]:hover,
+.label-default[href]:focus {
+ background-color: #5e5e5e;
+}
+.label-primary {
+ background-color: #337ab7;
+}
+.label-primary[href]:hover,
+.label-primary[href]:focus {
+ background-color: #286090;
+}
+.label-success {
+ background-color: #5cb85c;
+}
+.label-success[href]:hover,
+.label-success[href]:focus {
+ background-color: #449d44;
+}
+.label-info {
+ background-color: #5bc0de;
+}
+.label-info[href]:hover,
+.label-info[href]:focus {
+ background-color: #31b0d5;
+}
+.label-warning {
+ background-color: #f0ad4e;
+}
+.label-warning[href]:hover,
+.label-warning[href]:focus {
+ background-color: #ec971f;
+}
+.label-danger {
+ background-color: #d9534f;
+}
+.label-danger[href]:hover,
+.label-danger[href]:focus {
+ background-color: #c9302c;
+}
+.badge {
+ display: inline-block;
+ min-width: 10px;
+ padding: 3px 7px;
+ font-size: 12px;
+ font-weight: bold;
+ line-height: 1;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ background-color: #777;
+ border-radius: 10px;
+}
+.badge:empty {
+ display: none;
+}
+.btn .badge {
+ position: relative;
+ top: -1px;
+}
+.btn-xs .badge {
+ top: 0;
+ padding: 1px 5px;
+}
+a.badge:hover,
+a.badge:focus {
+ color: #fff;
+ text-decoration: none;
+ cursor: pointer;
+}
+.list-group-item.active > .badge,
+.nav-pills > .active > a > .badge {
+ color: #337ab7;
+ background-color: #fff;
+}
+.list-group-item > .badge {
+ float: right;
+}
+.list-group-item > .badge + .badge {
+ margin-right: 5px;
+}
+.nav-pills > li > a > .badge {
+ margin-left: 3px;
+}
+.jumbotron {
+ padding: 30px 15px;
+ margin-bottom: 30px;
+ color: inherit;
+ background-color: #eee;
+}
+.jumbotron h1,
+.jumbotron .h1 {
+ color: inherit;
+}
+.jumbotron p {
+ margin-bottom: 15px;
+ font-size: 21px;
+ font-weight: 200;
+}
+.jumbotron > hr {
+ border-top-color: #d5d5d5;
+}
+.container .jumbotron,
+.container-fluid .jumbotron {
+ border-radius: 6px;
+}
+.jumbotron .container {
+ max-width: 100%;
+}
+@media screen and (min-width: 768px) {
+ .jumbotron {
+ padding: 48px 0;
+ }
+ .container .jumbotron,
+ .container-fluid .jumbotron {
+ padding-right: 60px;
+ padding-left: 60px;
+ }
+ .jumbotron h1,
+ .jumbotron .h1 {
+ font-size: 63px;
+ }
+}
+.thumbnail {
+ display: block;
+ padding: 4px;
+ margin-bottom: 20px;
+ line-height: 1.42857143;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ -webkit-transition: border .2s ease-in-out;
+ -o-transition: border .2s ease-in-out;
+ transition: border .2s ease-in-out;
+}
+.thumbnail > img,
+.thumbnail a > img {
+ margin-right: auto;
+ margin-left: auto;
+}
+a.thumbnail:hover,
+a.thumbnail:focus,
+a.thumbnail.active {
+ border-color: #337ab7;
+}
+.thumbnail .caption {
+ padding: 9px;
+ color: #333;
+}
+.alert {
+ padding: 15px;
+ margin-bottom: 20px;
+ border: 1px solid transparent;
+ border-radius: 4px;
+}
+.alert h4 {
+ margin-top: 0;
+ color: inherit;
+}
+.alert .alert-link {
+ font-weight: bold;
+}
+.alert > p,
+.alert > ul {
+ margin-bottom: 0;
+}
+.alert > p + p {
+ margin-top: 5px;
+}
+.alert-dismissable,
+.alert-dismissible {
+ padding-right: 35px;
+}
+.alert-dismissable .close,
+.alert-dismissible .close {
+ position: relative;
+ top: -2px;
+ right: -21px;
+ color: inherit;
+}
+.alert-success {
+ color: #3c763d;
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+}
+.alert-success hr {
+ border-top-color: #c9e2b3;
+}
+.alert-success .alert-link {
+ color: #2b542c;
+}
+.alert-info {
+ color: #31708f;
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+}
+.alert-info hr {
+ border-top-color: #a6e1ec;
+}
+.alert-info .alert-link {
+ color: #245269;
+}
+.alert-warning {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+ border-color: #faebcc;
+}
+.alert-warning hr {
+ border-top-color: #f7e1b5;
+}
+.alert-warning .alert-link {
+ color: #66512c;
+}
+.alert-danger {
+ color: #a94442;
+ background-color: #f2dede;
+ border-color: #ebccd1;
+}
+.alert-danger hr {
+ border-top-color: #e4b9c0;
+}
+.alert-danger .alert-link {
+ color: #843534;
+}
+@-webkit-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+@-o-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+@keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+.progress {
+ height: 20px;
+ margin-bottom: 20px;
+ overflow: hidden;
+ background-color: #f5f5f5;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+}
+.progress-bar {
+ float: left;
+ width: 0;
+ height: 100%;
+ font-size: 12px;
+ line-height: 20px;
+ color: #fff;
+ text-align: center;
+ background-color: #337ab7;
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
+ -webkit-transition: width .6s ease;
+ -o-transition: width .6s ease;
+ transition: width .6s ease;
+}
+.progress-striped .progress-bar,
+.progress-bar-striped {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ -webkit-background-size: 40px 40px;
+ background-size: 40px 40px;
+}
+.progress.active .progress-bar,
+.progress-bar.active {
+ -webkit-animation: progress-bar-stripes 2s linear infinite;
+ -o-animation: progress-bar-stripes 2s linear infinite;
+ animation: progress-bar-stripes 2s linear infinite;
+}
+.progress-bar-success {
+ background-color: #5cb85c;
+}
+.progress-striped .progress-bar-success {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-info {
+ background-color: #5bc0de;
+}
+.progress-striped .progress-bar-info {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-warning {
+ background-color: #f0ad4e;
+}
+.progress-striped .progress-bar-warning {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-danger {
+ background-color: #d9534f;
+}
+.progress-striped .progress-bar-danger {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.media {
+ margin-top: 15px;
+}
+.media:first-child {
+ margin-top: 0;
+}
+.media-right,
+.media > .pull-right {
+ padding-left: 10px;
+}
+.media-left,
+.media > .pull-left {
+ padding-right: 10px;
+}
+.media-left,
+.media-right,
+.media-body {
+ display: table-cell;
+ vertical-align: top;
+}
+.media-middle {
+ vertical-align: middle;
+}
+.media-bottom {
+ vertical-align: bottom;
+}
+.media-heading {
+ margin-top: 0;
+ margin-bottom: 5px;
+}
+.media-list {
+ padding-left: 0;
+ list-style: none;
+}
+.list-group {
+ padding-left: 0;
+ margin-bottom: 20px;
+}
+.list-group-item {
+ position: relative;
+ display: block;
+ padding: 10px 15px;
+ margin-bottom: -1px;
+ background-color: #fff;
+ border: 1px solid #ddd;
+}
+.list-group-item:first-child {
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+}
+.list-group-item:last-child {
+ margin-bottom: 0;
+ border-bottom-right-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+a.list-group-item {
+ color: #555;
+}
+a.list-group-item .list-group-item-heading {
+ color: #333;
+}
+a.list-group-item:hover,
+a.list-group-item:focus {
+ color: #555;
+ text-decoration: none;
+ background-color: #f5f5f5;
+}
+.list-group-item.disabled,
+.list-group-item.disabled:hover,
+.list-group-item.disabled:focus {
+ color: #777;
+ cursor: not-allowed;
+ background-color: #eee;
+}
+.list-group-item.disabled .list-group-item-heading,
+.list-group-item.disabled:hover .list-group-item-heading,
+.list-group-item.disabled:focus .list-group-item-heading {
+ color: inherit;
+}
+.list-group-item.disabled .list-group-item-text,
+.list-group-item.disabled:hover .list-group-item-text,
+.list-group-item.disabled:focus .list-group-item-text {
+ color: #777;
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+ z-index: 2;
+ color: #fff;
+ background-color: #337ab7;
+ border-color: #337ab7;
+}
+.list-group-item.active .list-group-item-heading,
+.list-group-item.active:hover .list-group-item-heading,
+.list-group-item.active:focus .list-group-item-heading,
+.list-group-item.active .list-group-item-heading > small,
+.list-group-item.active:hover .list-group-item-heading > small,
+.list-group-item.active:focus .list-group-item-heading > small,
+.list-group-item.active .list-group-item-heading > .small,
+.list-group-item.active:hover .list-group-item-heading > .small,
+.list-group-item.active:focus .list-group-item-heading > .small {
+ color: inherit;
+}
+.list-group-item.active .list-group-item-text,
+.list-group-item.active:hover .list-group-item-text,
+.list-group-item.active:focus .list-group-item-text {
+ color: #c7ddef;
+}
+.list-group-item-success {
+ color: #3c763d;
+ background-color: #dff0d8;
+}
+a.list-group-item-success {
+ color: #3c763d;
+}
+a.list-group-item-success .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-success:hover,
+a.list-group-item-success:focus {
+ color: #3c763d;
+ background-color: #d0e9c6;
+}
+a.list-group-item-success.active,
+a.list-group-item-success.active:hover,
+a.list-group-item-success.active:focus {
+ color: #fff;
+ background-color: #3c763d;
+ border-color: #3c763d;
+}
+.list-group-item-info {
+ color: #31708f;
+ background-color: #d9edf7;
+}
+a.list-group-item-info {
+ color: #31708f;
+}
+a.list-group-item-info .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-info:hover,
+a.list-group-item-info:focus {
+ color: #31708f;
+ background-color: #c4e3f3;
+}
+a.list-group-item-info.active,
+a.list-group-item-info.active:hover,
+a.list-group-item-info.active:focus {
+ color: #fff;
+ background-color: #31708f;
+ border-color: #31708f;
+}
+.list-group-item-warning {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+}
+a.list-group-item-warning {
+ color: #8a6d3b;
+}
+a.list-group-item-warning .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-warning:hover,
+a.list-group-item-warning:focus {
+ color: #8a6d3b;
+ background-color: #faf2cc;
+}
+a.list-group-item-warning.active,
+a.list-group-item-warning.active:hover,
+a.list-group-item-warning.active:focus {
+ color: #fff;
+ background-color: #8a6d3b;
+ border-color: #8a6d3b;
+}
+.list-group-item-danger {
+ color: #a94442;
+ background-color: #f2dede;
+}
+a.list-group-item-danger {
+ color: #a94442;
+}
+a.list-group-item-danger .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-danger:hover,
+a.list-group-item-danger:focus {
+ color: #a94442;
+ background-color: #ebcccc;
+}
+a.list-group-item-danger.active,
+a.list-group-item-danger.active:hover,
+a.list-group-item-danger.active:focus {
+ color: #fff;
+ background-color: #a94442;
+ border-color: #a94442;
+}
+.list-group-item-heading {
+ margin-top: 0;
+ margin-bottom: 5px;
+}
+.list-group-item-text {
+ margin-bottom: 0;
+ line-height: 1.3;
+}
+.panel {
+ margin-bottom: 20px;
+ background-color: #fff;
+ border: 1px solid transparent;
+ border-radius: 4px;
+ -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+ box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+}
+.panel-body {
+ padding: 15px;
+}
+.panel-heading {
+ padding: 10px 15px;
+ border-bottom: 1px solid transparent;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel-heading > .dropdown .dropdown-toggle {
+ color: inherit;
+}
+.panel-title {
+ margin-top: 0;
+ margin-bottom: 0;
+ font-size: 16px;
+ color: inherit;
+}
+.panel-title > a {
+ color: inherit;
+}
+.panel-footer {
+ padding: 10px 15px;
+ background-color: #f5f5f5;
+ border-top: 1px solid #ddd;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .list-group,
+.panel > .panel-collapse > .list-group {
+ margin-bottom: 0;
+}
+.panel > .list-group .list-group-item,
+.panel > .panel-collapse > .list-group .list-group-item {
+ border-width: 1px 0;
+ border-radius: 0;
+}
+.panel > .list-group:first-child .list-group-item:first-child,
+.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
+ border-top: 0;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel > .list-group:last-child .list-group-item:last-child,
+.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
+ border-bottom: 0;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel-heading + .list-group .list-group-item:first-child {
+ border-top-width: 0;
+}
+.list-group + .panel-footer {
+ border-top-width: 0;
+}
+.panel > .table,
+.panel > .table-responsive > .table,
+.panel > .panel-collapse > .table {
+ margin-bottom: 0;
+}
+.panel > .table caption,
+.panel > .table-responsive > .table caption,
+.panel > .panel-collapse > .table caption {
+ padding-right: 15px;
+ padding-left: 15px;
+}
+.panel > .table:first-child,
+.panel > .table-responsive:first-child > .table:first-child {
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
+ border-top-left-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
+ border-top-right-radius: 3px;
+}
+.panel > .table:last-child,
+.panel > .table-responsive:last-child > .table:last-child {
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
+ border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
+ border-bottom-right-radius: 3px;
+}
+.panel > .panel-body + .table,
+.panel > .panel-body + .table-responsive,
+.panel > .table + .panel-body,
+.panel > .table-responsive + .panel-body {
+ border-top: 1px solid #ddd;
+}
+.panel > .table > tbody:first-child > tr:first-child th,
+.panel > .table > tbody:first-child > tr:first-child td {
+ border-top: 0;
+}
+.panel > .table-bordered,
+.panel > .table-responsive > .table-bordered {
+ border: 0;
+}
+.panel > .table-bordered > thead > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
+.panel > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-bordered > thead > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
+.panel > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-bordered > tfoot > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+ border-left: 0;
+}
+.panel > .table-bordered > thead > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
+.panel > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-bordered > thead > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
+.panel > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-bordered > tfoot > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+ border-right: 0;
+}
+.panel > .table-bordered > thead > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
+.panel > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-bordered > thead > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
+.panel > .table-bordered > tbody > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
+ border-bottom: 0;
+}
+.panel > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-bordered > tfoot > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
+ border-bottom: 0;
+}
+.panel > .table-responsive {
+ margin-bottom: 0;
+ border: 0;
+}
+.panel-group {
+ margin-bottom: 20px;
+}
+.panel-group .panel {
+ margin-bottom: 0;
+ border-radius: 4px;
+}
+.panel-group .panel + .panel {
+ margin-top: 5px;
+}
+.panel-group .panel-heading {
+ border-bottom: 0;
+}
+.panel-group .panel-heading + .panel-collapse > .panel-body,
+.panel-group .panel-heading + .panel-collapse > .list-group {
+ border-top: 1px solid #ddd;
+}
+.panel-group .panel-footer {
+ border-top: 0;
+}
+.panel-group .panel-footer + .panel-collapse .panel-body {
+ border-bottom: 1px solid #ddd;
+}
+.panel-default {
+ border-color: #ddd;
+}
+.panel-default > .panel-heading {
+ color: #333;
+ background-color: #f5f5f5;
+ border-color: #ddd;
+}
+.panel-default > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #ddd;
+}
+.panel-default > .panel-heading .badge {
+ color: #f5f5f5;
+ background-color: #333;
+}
+.panel-default > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #ddd;
+}
+.panel-primary {
+ border-color: #337ab7;
+}
+.panel-primary > .panel-heading {
+ color: #fff;
+ background-color: #337ab7;
+ border-color: #337ab7;
+}
+.panel-primary > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #337ab7;
+}
+.panel-primary > .panel-heading .badge {
+ color: #337ab7;
+ background-color: #fff;
+}
+.panel-primary > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #337ab7;
+}
+.panel-success {
+ border-color: #d6e9c6;
+}
+.panel-success > .panel-heading {
+ color: #3c763d;
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+}
+.panel-success > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #d6e9c6;
+}
+.panel-success > .panel-heading .badge {
+ color: #dff0d8;
+ background-color: #3c763d;
+}
+.panel-success > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #d6e9c6;
+}
+.panel-info {
+ border-color: #bce8f1;
+}
+.panel-info > .panel-heading {
+ color: #31708f;
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+}
+.panel-info > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #bce8f1;
+}
+.panel-info > .panel-heading .badge {
+ color: #d9edf7;
+ background-color: #31708f;
+}
+.panel-info > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #bce8f1;
+}
+.panel-warning {
+ border-color: #faebcc;
+}
+.panel-warning > .panel-heading {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+ border-color: #faebcc;
+}
+.panel-warning > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #faebcc;
+}
+.panel-warning > .panel-heading .badge {
+ color: #fcf8e3;
+ background-color: #8a6d3b;
+}
+.panel-warning > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #faebcc;
+}
+.panel-danger {
+ border-color: #ebccd1;
+}
+.panel-danger > .panel-heading {
+ color: #a94442;
+ background-color: #f2dede;
+ border-color: #ebccd1;
+}
+.panel-danger > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #ebccd1;
+}
+.panel-danger > .panel-heading .badge {
+ color: #f2dede;
+ background-color: #a94442;
+}
+.panel-danger > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #ebccd1;
+}
+.embed-responsive {
+ position: relative;
+ display: block;
+ height: 0;
+ padding: 0;
+ overflow: hidden;
+}
+.embed-responsive .embed-responsive-item,
+.embed-responsive iframe,
+.embed-responsive embed,
+.embed-responsive object,
+.embed-responsive video {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border: 0;
+}
+.embed-responsive.embed-responsive-16by9 {
+ padding-bottom: 56.25%;
+}
+.embed-responsive.embed-responsive-4by3 {
+ padding-bottom: 75%;
+}
+.well {
+ min-height: 20px;
+ padding: 19px;
+ margin-bottom: 20px;
+ background-color: #f5f5f5;
+ border: 1px solid #e3e3e3;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
+}
+.well blockquote {
+ border-color: #ddd;
+ border-color: rgba(0, 0, 0, .15);
+}
+.well-lg {
+ padding: 24px;
+ border-radius: 6px;
+}
+.well-sm {
+ padding: 9px;
+ border-radius: 3px;
+}
+.close {
+ float: right;
+ font-size: 21px;
+ font-weight: bold;
+ line-height: 1;
+ color: #000;
+ text-shadow: 0 1px 0 #fff;
+ filter: alpha(opacity=20);
+ opacity: .2;
+}
+.close:hover,
+.close:focus {
+ color: #000;
+ text-decoration: none;
+ cursor: pointer;
+ filter: alpha(opacity=50);
+ opacity: .5;
+}
+button.close {
+ -webkit-appearance: none;
+ padding: 0;
+ cursor: pointer;
+ background: transparent;
+ border: 0;
+}
+.modal-open {
+ overflow: hidden;
+}
+.modal {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1040;
+ display: none;
+ overflow: hidden;
+ -webkit-overflow-scrolling: touch;
+ outline: 0;
+}
+.modal.fade .modal-dialog {
+ -webkit-transition: -webkit-transform .3s ease-out;
+ -o-transition: -o-transform .3s ease-out;
+ transition: transform .3s ease-out;
+ -webkit-transform: translate(0, -25%);
+ -ms-transform: translate(0, -25%);
+ -o-transform: translate(0, -25%);
+ transform: translate(0, -25%);
+}
+.modal.in .modal-dialog {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ -o-transform: translate(0, 0);
+ transform: translate(0, 0);
+}
+.modal-open .modal {
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+.modal-dialog {
+ position: relative;
+ width: auto;
+ margin: 10px;
+}
+.modal-content {
+ position: relative;
+ background-color: #fff;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ border: 1px solid #999;
+ border: 1px solid rgba(0, 0, 0, .2);
+ border-radius: 6px;
+ outline: 0;
+ -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
+ box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
+}
+.modal-backdrop {
+ position: absolute;
+ top: 0;
+ right: 0;
+ left: 0;
+ background-color: #000;
+}
+.modal-backdrop.fade {
+ filter: alpha(opacity=0);
+ opacity: 0;
+}
+.modal-backdrop.in {
+ filter: alpha(opacity=50);
+ opacity: .5;
+}
+.modal-header {
+ min-height: 16.42857143px;
+ padding: 15px;
+ border-bottom: 1px solid #e5e5e5;
+}
+.modal-header .close {
+ margin-top: -2px;
+}
+.modal-title {
+ margin: 0;
+ line-height: 1.42857143;
+}
+.modal-body {
+ position: relative;
+ padding: 15px;
+}
+.modal-footer {
+ padding: 15px;
+ text-align: right;
+ border-top: 1px solid #e5e5e5;
+}
+.modal-footer .btn + .btn {
+ margin-bottom: 0;
+ margin-left: 5px;
+}
+.modal-footer .btn-group .btn + .btn {
+ margin-left: -1px;
+}
+.modal-footer .btn-block + .btn-block {
+ margin-left: 0;
+}
+.modal-scrollbar-measure {
+ position: absolute;
+ top: -9999px;
+ width: 50px;
+ height: 50px;
+ overflow: scroll;
+}
+@media (min-width: 768px) {
+ .modal-dialog {
+ width: 600px;
+ margin: 30px auto;
+ }
+ .modal-content {
+ -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
+ box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
+ }
+ .modal-sm {
+ width: 300px;
+ }
+}
+@media (min-width: 992px) {
+ .modal-lg {
+ width: 900px;
+ }
+}
+.tooltip {
+ position: absolute;
+ z-index: 1070;
+ display: block;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 12px;
+ font-weight: normal;
+ line-height: 1.4;
+ visibility: visible;
+ filter: alpha(opacity=0);
+ opacity: 0;
+}
+.tooltip.in {
+ filter: alpha(opacity=90);
+ opacity: .9;
+}
+.tooltip.top {
+ padding: 5px 0;
+ margin-top: -3px;
+}
+.tooltip.right {
+ padding: 0 5px;
+ margin-left: 3px;
+}
+.tooltip.bottom {
+ padding: 5px 0;
+ margin-top: 3px;
+}
+.tooltip.left {
+ padding: 0 5px;
+ margin-left: -3px;
+}
+.tooltip-inner {
+ max-width: 200px;
+ padding: 3px 8px;
+ color: #fff;
+ text-align: center;
+ text-decoration: none;
+ background-color: #000;
+ border-radius: 4px;
+}
+.tooltip-arrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+.tooltip.top .tooltip-arrow {
+ bottom: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000;
+}
+.tooltip.top-left .tooltip-arrow {
+ right: 5px;
+ bottom: 0;
+ margin-bottom: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000;
+}
+.tooltip.top-right .tooltip-arrow {
+ bottom: 0;
+ left: 5px;
+ margin-bottom: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000;
+}
+.tooltip.right .tooltip-arrow {
+ top: 50%;
+ left: 0;
+ margin-top: -5px;
+ border-width: 5px 5px 5px 0;
+ border-right-color: #000;
+}
+.tooltip.left .tooltip-arrow {
+ top: 50%;
+ right: 0;
+ margin-top: -5px;
+ border-width: 5px 0 5px 5px;
+ border-left-color: #000;
+}
+.tooltip.bottom .tooltip-arrow {
+ top: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000;
+}
+.tooltip.bottom-left .tooltip-arrow {
+ top: 0;
+ right: 5px;
+ margin-top: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000;
+}
+.tooltip.bottom-right .tooltip-arrow {
+ top: 0;
+ left: 5px;
+ margin-top: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000;
+}
+.popover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1060;
+ display: none;
+ max-width: 276px;
+ padding: 1px;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 1.42857143;
+ text-align: left;
+ white-space: normal;
+ background-color: #fff;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, .2);
+ border-radius: 6px;
+ -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+}
+.popover.top {
+ margin-top: -10px;
+}
+.popover.right {
+ margin-left: 10px;
+}
+.popover.bottom {
+ margin-top: 10px;
+}
+.popover.left {
+ margin-left: -10px;
+}
+.popover-title {
+ padding: 8px 14px;
+ margin: 0;
+ font-size: 14px;
+ background-color: #f7f7f7;
+ border-bottom: 1px solid #ebebeb;
+ border-radius: 5px 5px 0 0;
+}
+.popover-content {
+ padding: 9px 14px;
+}
+.popover > .arrow,
+.popover > .arrow:after {
+ position: absolute;
+ display: block;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+.popover > .arrow {
+ border-width: 11px;
+}
+.popover > .arrow:after {
+ content: "";
+ border-width: 10px;
+}
+.popover.top > .arrow {
+ bottom: -11px;
+ left: 50%;
+ margin-left: -11px;
+ border-top-color: #999;
+ border-top-color: rgba(0, 0, 0, .25);
+ border-bottom-width: 0;
+}
+.popover.top > .arrow:after {
+ bottom: 1px;
+ margin-left: -10px;
+ content: " ";
+ border-top-color: #fff;
+ border-bottom-width: 0;
+}
+.popover.right > .arrow {
+ top: 50%;
+ left: -11px;
+ margin-top: -11px;
+ border-right-color: #999;
+ border-right-color: rgba(0, 0, 0, .25);
+ border-left-width: 0;
+}
+.popover.right > .arrow:after {
+ bottom: -10px;
+ left: 1px;
+ content: " ";
+ border-right-color: #fff;
+ border-left-width: 0;
+}
+.popover.bottom > .arrow {
+ top: -11px;
+ left: 50%;
+ margin-left: -11px;
+ border-top-width: 0;
+ border-bottom-color: #999;
+ border-bottom-color: rgba(0, 0, 0, .25);
+}
+.popover.bottom > .arrow:after {
+ top: 1px;
+ margin-left: -10px;
+ content: " ";
+ border-top-width: 0;
+ border-bottom-color: #fff;
+}
+.popover.left > .arrow {
+ top: 50%;
+ right: -11px;
+ margin-top: -11px;
+ border-right-width: 0;
+ border-left-color: #999;
+ border-left-color: rgba(0, 0, 0, .25);
+}
+.popover.left > .arrow:after {
+ right: 1px;
+ bottom: -10px;
+ content: " ";
+ border-right-width: 0;
+ border-left-color: #fff;
+}
+.carousel {
+ position: relative;
+}
+.carousel-inner {
+ position: relative;
+ width: 100%;
+ overflow: hidden;
+}
+.carousel-inner > .item {
+ position: relative;
+ display: none;
+ -webkit-transition: .6s ease-in-out left;
+ -o-transition: .6s ease-in-out left;
+ transition: .6s ease-in-out left;
+}
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+ line-height: 1;
+}
+@media all and (transform-3d), (-webkit-transform-3d) {
+ .carousel-inner > .item {
+ -webkit-transition: -webkit-transform .6s ease-in-out;
+ -o-transition: -o-transform .6s ease-in-out;
+ transition: transform .6s ease-in-out;
+
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ -webkit-perspective: 1000;
+ perspective: 1000;
+ }
+ .carousel-inner > .item.next,
+ .carousel-inner > .item.active.right {
+ left: 0;
+ -webkit-transform: translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0);
+ }
+ .carousel-inner > .item.prev,
+ .carousel-inner > .item.active.left {
+ left: 0;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+ }
+ .carousel-inner > .item.next.left,
+ .carousel-inner > .item.prev.right,
+ .carousel-inner > .item.active {
+ left: 0;
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+}
+.carousel-inner > .active,
+.carousel-inner > .next,
+.carousel-inner > .prev {
+ display: block;
+}
+.carousel-inner > .active {
+ left: 0;
+}
+.carousel-inner > .next,
+.carousel-inner > .prev {
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+.carousel-inner > .next {
+ left: 100%;
+}
+.carousel-inner > .prev {
+ left: -100%;
+}
+.carousel-inner > .next.left,
+.carousel-inner > .prev.right {
+ left: 0;
+}
+.carousel-inner > .active.left {
+ left: -100%;
+}
+.carousel-inner > .active.right {
+ left: 100%;
+}
+.carousel-control {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 15%;
+ font-size: 20px;
+ color: #fff;
+ text-align: center;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
+ filter: alpha(opacity=50);
+ opacity: .5;
+}
+.carousel-control.left {
+ background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+ background-image: -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+ background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));
+ background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
+ background-repeat: repeat-x;
+}
+.carousel-control.right {
+ right: 0;
+ left: auto;
+ background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+ background-image: -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+ background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));
+ background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
+ background-repeat: repeat-x;
+}
+.carousel-control:hover,
+.carousel-control:focus {
+ color: #fff;
+ text-decoration: none;
+ filter: alpha(opacity=90);
+ outline: 0;
+ opacity: .9;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-left,
+.carousel-control .glyphicon-chevron-right {
+ position: absolute;
+ top: 50%;
+ z-index: 5;
+ display: inline-block;
+}
+.carousel-control .icon-prev,
+.carousel-control .glyphicon-chevron-left {
+ left: 50%;
+ margin-left: -10px;
+}
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-right {
+ right: 50%;
+ margin-right: -10px;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next {
+ width: 20px;
+ height: 20px;
+ margin-top: -10px;
+ font-family: serif;
+}
+.carousel-control .icon-prev:before {
+ content: '\2039';
+}
+.carousel-control .icon-next:before {
+ content: '\203a';
+}
+.carousel-indicators {
+ position: absolute;
+ bottom: 10px;
+ left: 50%;
+ z-index: 15;
+ width: 60%;
+ padding-left: 0;
+ margin-left: -30%;
+ text-align: center;
+ list-style: none;
+}
+.carousel-indicators li {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ margin: 1px;
+ text-indent: -999px;
+ cursor: pointer;
+ background-color: #000 \9;
+ background-color: rgba(0, 0, 0, 0);
+ border: 1px solid #fff;
+ border-radius: 10px;
+}
+.carousel-indicators .active {
+ width: 12px;
+ height: 12px;
+ margin: 0;
+ background-color: #fff;
+}
+.carousel-caption {
+ position: absolute;
+ right: 15%;
+ bottom: 20px;
+ left: 15%;
+ z-index: 10;
+ padding-top: 20px;
+ padding-bottom: 20px;
+ color: #fff;
+ text-align: center;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
+}
+.carousel-caption .btn {
+ text-shadow: none;
+}
+@media screen and (min-width: 768px) {
+ .carousel-control .glyphicon-chevron-left,
+ .carousel-control .glyphicon-chevron-right,
+ .carousel-control .icon-prev,
+ .carousel-control .icon-next {
+ width: 30px;
+ height: 30px;
+ margin-top: -15px;
+ font-size: 30px;
+ }
+ .carousel-control .glyphicon-chevron-left,
+ .carousel-control .icon-prev {
+ margin-left: -15px;
+ }
+ .carousel-control .glyphicon-chevron-right,
+ .carousel-control .icon-next {
+ margin-right: -15px;
+ }
+ .carousel-caption {
+ right: 20%;
+ left: 20%;
+ padding-bottom: 30px;
+ }
+ .carousel-indicators {
+ bottom: 20px;
+ }
+}
+.clearfix:before,
+.clearfix:after,
+.dl-horizontal dd:before,
+.dl-horizontal dd:after,
+.container:before,
+.container:after,
+.container-fluid:before,
+.container-fluid:after,
+.row:before,
+.row:after,
+.form-horizontal .form-group:before,
+.form-horizontal .form-group:after,
+.btn-toolbar:before,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:before,
+.btn-group-vertical > .btn-group:after,
+.nav:before,
+.nav:after,
+.navbar:before,
+.navbar:after,
+.navbar-header:before,
+.navbar-header:after,
+.navbar-collapse:before,
+.navbar-collapse:after,
+.pager:before,
+.pager:after,
+.panel-body:before,
+.panel-body:after,
+.modal-footer:before,
+.modal-footer:after {
+ display: table;
+ content: " ";
+}
+.clearfix:after,
+.dl-horizontal dd:after,
+.container:after,
+.container-fluid:after,
+.row:after,
+.form-horizontal .form-group:after,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:after,
+.nav:after,
+.navbar:after,
+.navbar-header:after,
+.navbar-collapse:after,
+.pager:after,
+.panel-body:after,
+.modal-footer:after {
+ clear: both;
+}
+.center-block {
+ display: block;
+ margin-right: auto;
+ margin-left: auto;
+}
+.pull-right {
+ float: right !important;
+}
+.pull-left {
+ float: left !important;
+}
+.hide {
+ display: none !important;
+}
+.show {
+ display: block !important;
+}
+.invisible {
+ visibility: hidden;
+}
+.text-hide {
+ font: 0/0 a;
+ color: transparent;
+ text-shadow: none;
+ background-color: transparent;
+ border: 0;
+}
+.hidden {
+ display: none !important;
+ visibility: hidden !important;
+}
+.affix {
+ position: fixed;
+}
+@-ms-viewport {
+ width: device-width;
+}
+.visible-xs,
+.visible-sm,
+.visible-md,
+.visible-lg {
+ display: none !important;
+}
+.visible-xs-block,
+.visible-xs-inline,
+.visible-xs-inline-block,
+.visible-sm-block,
+.visible-sm-inline,
+.visible-sm-inline-block,
+.visible-md-block,
+.visible-md-inline,
+.visible-md-inline-block,
+.visible-lg-block,
+.visible-lg-inline,
+.visible-lg-inline-block {
+ display: none !important;
+}
+@media (max-width: 767px) {
+ .visible-xs {
+ display: block !important;
+ }
+ table.visible-xs {
+ display: table;
+ }
+ tr.visible-xs {
+ display: table-row !important;
+ }
+ th.visible-xs,
+ td.visible-xs {
+ display: table-cell !important;
+ }
+}
+@media (max-width: 767px) {
+ .visible-xs-block {
+ display: block !important;
+ }
+}
+@media (max-width: 767px) {
+ .visible-xs-inline {
+ display: inline !important;
+ }
+}
+@media (max-width: 767px) {
+ .visible-xs-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm {
+ display: block !important;
+ }
+ table.visible-sm {
+ display: table;
+ }
+ tr.visible-sm {
+ display: table-row !important;
+ }
+ th.visible-sm,
+ td.visible-sm {
+ display: table-cell !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm-block {
+ display: block !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm-inline {
+ display: inline !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md {
+ display: block !important;
+ }
+ table.visible-md {
+ display: table;
+ }
+ tr.visible-md {
+ display: table-row !important;
+ }
+ th.visible-md,
+ td.visible-md {
+ display: table-cell !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md-block {
+ display: block !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md-inline {
+ display: inline !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg {
+ display: block !important;
+ }
+ table.visible-lg {
+ display: table;
+ }
+ tr.visible-lg {
+ display: table-row !important;
+ }
+ th.visible-lg,
+ td.visible-lg {
+ display: table-cell !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg-block {
+ display: block !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg-inline {
+ display: inline !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (max-width: 767px) {
+ .hidden-xs {
+ display: none !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .hidden-sm {
+ display: none !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .hidden-md {
+ display: none !important;
+ }
+}
+@media (min-width: 1200px) {
+ .hidden-lg {
+ display: none !important;
+ }
+}
+.visible-print {
+ display: none !important;
+}
+@media print {
+ .visible-print {
+ display: block !important;
+ }
+ table.visible-print {
+ display: table;
+ }
+ tr.visible-print {
+ display: table-row !important;
+ }
+ th.visible-print,
+ td.visible-print {
+ display: table-cell !important;
+ }
+}
+.visible-print-block {
+ display: none !important;
+}
+@media print {
+ .visible-print-block {
+ display: block !important;
+ }
+}
+.visible-print-inline {
+ display: none !important;
+}
+@media print {
+ .visible-print-inline {
+ display: inline !important;
+ }
+}
+.visible-print-inline-block {
+ display: none !important;
+}
+@media print {
+ .visible-print-inline-block {
+ display: inline-block !important;
+ }
+}
+@media print {
+ .hidden-print {
+ display: none !important;
+ }
+}
+/*# sourceMappingURL=bootstrap.css.map */
diff --git a/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap.css.map b/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap.css.map
new file mode 100644
index 00000000..a02f6ba0
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["bootstrap.css","less/normalize.less","less/print.less","less/glyphicons.less","less/scaffolding.less","less/mixins/vendor-prefixes.less","less/mixins/tab-focus.less","less/mixins/image.less","less/type.less","less/mixins/text-emphasis.less","less/mixins/background-variant.less","less/mixins/text-overflow.less","less/code.less","less/grid.less","less/mixins/grid.less","less/mixins/grid-framework.less","less/tables.less","less/mixins/table-row.less","less/forms.less","less/mixins/forms.less","less/buttons.less","less/mixins/buttons.less","less/mixins/opacity.less","less/component-animations.less","less/dropdowns.less","less/mixins/nav-divider.less","less/mixins/reset-filter.less","less/button-groups.less","less/mixins/border-radius.less","less/input-groups.less","less/navs.less","less/navbar.less","less/mixins/nav-vertical-align.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/mixins/pagination.less","less/pager.less","less/labels.less","less/mixins/labels.less","less/badges.less","less/jumbotron.less","less/thumbnails.less","less/alerts.less","less/mixins/alerts.less","less/progress-bars.less","less/mixins/gradients.less","less/mixins/progress-bar.less","less/media.less","less/list-group.less","less/mixins/list-group.less","less/panels.less","less/mixins/panels.less","less/responsive-embed.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/popovers.less","less/carousel.less","less/mixins/clearfix.less","less/mixins/center-block.less","less/mixins/hide-text.less","less/responsive-utilities.less","less/mixins/responsive-visibility.less"],"names":[],"mappings":"AAAA,6DAA4D;ACQ5D;EACE,yBAAA;EACA,4BAAA;EACA,gCAAA;EDND;ACaD;EACE,WAAA;EDXD;ACwBD;;;;;;;;;;;;;EAaE,gBAAA;EDtBD;AC8BD;;;;EAIE,uBAAA;EACA,0BAAA;ED5BD;ACoCD;EACE,eAAA;EACA,WAAA;EDlCD;AC0CD;;EAEE,eAAA;EDxCD;ACkDD;EACE,+BAAA;EDhDD;ACuDD;;EAEE,YAAA;EDrDD;AC+DD;EACE,2BAAA;ED7DD;ACoED;;EAEE,mBAAA;EDlED;ACyED;EACE,oBAAA;EDvED;AC+ED;EACE,gBAAA;EACA,kBAAA;ED7ED;ACoFD;EACE,kBAAA;EACA,aAAA;EDlFD;ACyFD;EACE,gBAAA;EDvFD;AC8FD;;EAEE,gBAAA;EACA,gBAAA;EACA,oBAAA;EACA,0BAAA;ED5FD;AC+FD;EACE,aAAA;ED7FD;ACgGD;EACE,iBAAA;ED9FD;ACwGD;EACE,WAAA;EDtGD;AC6GD;EACE,kBAAA;ED3GD;ACqHD;EACE,kBAAA;EDnHD;AC0HD;EACE,8BAAA;EACA,iCAAA;UAAA,yBAAA;EACA,WAAA;EDxHD;AC+HD;EACE,gBAAA;ED7HD;ACoID;;;;EAIE,mCAAA;EACA,gBAAA;EDlID;ACoJD;;;;;EAKE,gBAAA;EACA,eAAA;EACA,WAAA;EDlJD;ACyJD;EACE,mBAAA;EDvJD;ACiKD;;EAEE,sBAAA;ED/JD;AC0KD;;;;EAIE,4BAAA;EACA,iBAAA;EDxKD;AC+KD;;EAEE,iBAAA;ED7KD;ACoLD;;EAEE,WAAA;EACA,YAAA;EDlLD;AC0LD;EACE,qBAAA;EDxLD;ACmMD;;EAEE,gCAAA;KAAA,6BAAA;UAAA,wBAAA;EACA,YAAA;EDjMD;AC0MD;;EAEE,cAAA;EDxMD;ACiND;EACE,+BAAA;EACA,8BAAA;EACA,iCAAA;EACA,yBAAA;ED/MD;ACwND;;EAEE,0BAAA;EDtND;AC6ND;EACE,2BAAA;EACA,eAAA;EACA,gCAAA;ED3ND;ACmOD;EACE,WAAA;EACA,YAAA;EDjOD;ACwOD;EACE,gBAAA;EDtOD;AC8OD;EACE,mBAAA;ED5OD;ACsPD;EACE,2BAAA;EACA,mBAAA;EDpPD;ACuPD;;EAEE,YAAA;EDrPD;AACD,sFAAqF;AE1ErF;EAnGI;;;IAGI,oCAAA;IACA,wBAAA;IACA,qCAAA;YAAA,6BAAA;IACA,8BAAA;IFgLL;EE7KC;;IAEI,4BAAA;IF+KL;EE5KC;IACI,8BAAA;IF8KL;EE3KC;IACI,+BAAA;IF6KL;EExKC;;IAEI,aAAA;IF0KL;EEvKC;;IAEI,wBAAA;IACA,0BAAA;IFyKL;EEtKC;IACI,6BAAA;IFwKL;EErKC;;IAEI,0BAAA;IFuKL;EEpKC;IACI,4BAAA;IFsKL;EEnKC;;;IAGI,YAAA;IACA,WAAA;IFqKL;EElKC;;IAEI,yBAAA;IFoKL;EE7JC;IACI,6BAAA;IF+JL;EE3JC;IACI,eAAA;IF6JL;EE3JC;;IAGQ,mCAAA;IF4JT;EEzJC;IACI,wBAAA;IF2JL;EExJC;IACI,sCAAA;IF0JL;EE3JC;;IAKQ,mCAAA;IF0JT;EEvJC;;IAGQ,mCAAA;IFwJT;EACF;AGpPD;EACE,qCAAA;EACA,uDAAA;EACA,6TAAA;EHsPD;AG/OD;EACE,oBAAA;EACA,UAAA;EACA,uBAAA;EACA,qCAAA;EACA,oBAAA;EACA,qBAAA;EACA,gBAAA;EACA,qCAAA;EACA,oCAAA;EHiPD;AG7OmC;EAAW,gBAAA;EHgP9C;AG/OmC;EAAW,gBAAA;EHkP9C;AGhPmC;;EAAW,kBAAA;EHoP9C;AGnPmC;EAAW,kBAAA;EHsP9C;AGrPmC;EAAW,kBAAA;EHwP9C;AGvPmC;EAAW,kBAAA;EH0P9C;AGzPmC;EAAW,kBAAA;EH4P9C;AG3PmC;EAAW,kBAAA;EH8P9C;AG7PmC;EAAW,kBAAA;EHgQ9C;AG/PmC;EAAW,kBAAA;EHkQ9C;AGjQmC;EAAW,kBAAA;EHoQ9C;AGnQmC;EAAW,kBAAA;EHsQ9C;AGrQmC;EAAW,kBAAA;EHwQ9C;AGvQmC;EAAW,kBAAA;EH0Q9C;AGzQmC;EAAW,kBAAA;EH4Q9C;AG3QmC;EAAW,kBAAA;EH8Q9C;AG7QmC;EAAW,kBAAA;EHgR9C;AG/QmC;EAAW,kBAAA;EHkR9C;AGjRmC;EAAW,kBAAA;EHoR9C;AGnRmC;EAAW,kBAAA;EHsR9C;AGrRmC;EAAW,kBAAA;EHwR9C;AGvRmC;EAAW,kBAAA;EH0R9C;AGzRmC;EAAW,kBAAA;EH4R9C;AG3RmC;EAAW,kBAAA;EH8R9C;AG7RmC;EAAW,kBAAA;EHgS9C;AG/RmC;EAAW,kBAAA;EHkS9C;AGjSmC;EAAW,kBAAA;EHoS9C;AGnSmC;EAAW,kBAAA;EHsS9C;AGrSmC;EAAW,kBAAA;EHwS9C;AGvSmC;EAAW,kBAAA;EH0S9C;AGzSmC;EAAW,kBAAA;EH4S9C;AG3SmC;EAAW,kBAAA;EH8S9C;AG7SmC;EAAW,kBAAA;EHgT9C;AG/SmC;EAAW,kBAAA;EHkT9C;AGjTmC;EAAW,kBAAA;EHoT9C;AGnTmC;EAAW,kBAAA;EHsT9C;AGrTmC;EAAW,kBAAA;EHwT9C;AGvTmC;EAAW,kBAAA;EH0T9C;AGzTmC;EAAW,kBAAA;EH4T9C;AG3TmC;EAAW,kBAAA;EH8T9C;AG7TmC;EAAW,kBAAA;EHgU9C;AG/TmC;EAAW,kBAAA;EHkU9C;AGjUmC;EAAW,kBAAA;EHoU9C;AGnUmC;EAAW,kBAAA;EHsU9C;AGrUmC;EAAW,kBAAA;EHwU9C;AGvUmC;EAAW,kBAAA;EH0U9C;AGzUmC;EAAW,kBAAA;EH4U9C;AG3UmC;EAAW,kBAAA;EH8U9C;AG7UmC;EAAW,kBAAA;EHgV9C;AG/UmC;EAAW,kBAAA;EHkV9C;AGjVmC;EAAW,kBAAA;EHoV9C;AGnVmC;EAAW,kBAAA;EHsV9C;AGrVmC;EAAW,kBAAA;EHwV9C;AGvVmC;EAAW,kBAAA;EH0V9C;AGzVmC;EAAW,kBAAA;EH4V9C;AG3VmC;EAAW,kBAAA;EH8V9C;AG7VmC;EAAW,kBAAA;EHgW9C;AG/VmC;EAAW,kBAAA;EHkW9C;AGjWmC;EAAW,kBAAA;EHoW9C;AGnWmC;EAAW,kBAAA;EHsW9C;AGrWmC;EAAW,kBAAA;EHwW9C;AGvWmC;EAAW,kBAAA;EH0W9C;AGzWmC;EAAW,kBAAA;EH4W9C;AG3WmC;EAAW,kBAAA;EH8W9C;AG7WmC;EAAW,kBAAA;EHgX9C;AG/WmC;EAAW,kBAAA;EHkX9C;AGjXmC;EAAW,kBAAA;EHoX9C;AGnXmC;EAAW,kBAAA;EHsX9C;AGrXmC;EAAW,kBAAA;EHwX9C;AGvXmC;EAAW,kBAAA;EH0X9C;AGzXmC;EAAW,kBAAA;EH4X9C;AG3XmC;EAAW,kBAAA;EH8X9C;AG7XmC;EAAW,kBAAA;EHgY9C;AG/XmC;EAAW,kBAAA;EHkY9C;AGjYmC;EAAW,kBAAA;EHoY9C;AGnYmC;EAAW,kBAAA;EHsY9C;AGrYmC;EAAW,kBAAA;EHwY9C;AGvYmC;EAAW,kBAAA;EH0Y9C;AGzYmC;EAAW,kBAAA;EH4Y9C;AG3YmC;EAAW,kBAAA;EH8Y9C;AG7YmC;EAAW,kBAAA;EHgZ9C;AG/YmC;EAAW,kBAAA;EHkZ9C;AGjZmC;EAAW,kBAAA;EHoZ9C;AGnZmC;EAAW,kBAAA;EHsZ9C;AGrZmC;EAAW,kBAAA;EHwZ9C;AGvZmC;EAAW,kBAAA;EH0Z9C;AGzZmC;EAAW,kBAAA;EH4Z9C;AG3ZmC;EAAW,kBAAA;EH8Z9C;AG7ZmC;EAAW,kBAAA;EHga9C;AG/ZmC;EAAW,kBAAA;EHka9C;AGjamC;EAAW,kBAAA;EHoa9C;AGnamC;EAAW,kBAAA;EHsa9C;AGramC;EAAW,kBAAA;EHwa9C;AGvamC;EAAW,kBAAA;EH0a9C;AGzamC;EAAW,kBAAA;EH4a9C;AG3amC;EAAW,kBAAA;EH8a9C;AG7amC;EAAW,kBAAA;EHgb9C;AG/amC;EAAW,kBAAA;EHkb9C;AGjbmC;EAAW,kBAAA;EHob9C;AGnbmC;EAAW,kBAAA;EHsb9C;AGrbmC;EAAW,kBAAA;EHwb9C;AGvbmC;EAAW,kBAAA;EH0b9C;AGzbmC;EAAW,kBAAA;EH4b9C;AG3bmC;EAAW,kBAAA;EH8b9C;AG7bmC;EAAW,kBAAA;EHgc9C;AG/bmC;EAAW,kBAAA;EHkc9C;AGjcmC;EAAW,kBAAA;EHoc9C;AGncmC;EAAW,kBAAA;EHsc9C;AGrcmC;EAAW,kBAAA;EHwc9C;AGvcmC;EAAW,kBAAA;EH0c9C;AGzcmC;EAAW,kBAAA;EH4c9C;AG3cmC;EAAW,kBAAA;EH8c9C;AG7cmC;EAAW,kBAAA;EHgd9C;AG/cmC;EAAW,kBAAA;EHkd9C;AGjdmC;EAAW,kBAAA;EHod9C;AGndmC;EAAW,kBAAA;EHsd9C;AGrdmC;EAAW,kBAAA;EHwd9C;AGvdmC;EAAW,kBAAA;EH0d9C;AGzdmC;EAAW,kBAAA;EH4d9C;AG3dmC;EAAW,kBAAA;EH8d9C;AG7dmC;EAAW,kBAAA;EHge9C;AG/dmC;EAAW,kBAAA;EHke9C;AGjemC;EAAW,kBAAA;EHoe9C;AGnemC;EAAW,kBAAA;EHse9C;AGremC;EAAW,kBAAA;EHwe9C;AGvemC;EAAW,kBAAA;EH0e9C;AGzemC;EAAW,kBAAA;EH4e9C;AG3emC;EAAW,kBAAA;EH8e9C;AG7emC;EAAW,kBAAA;EHgf9C;AG/emC;EAAW,kBAAA;EHkf9C;AGjfmC;EAAW,kBAAA;EHof9C;AGnfmC;EAAW,kBAAA;EHsf9C;AGrfmC;EAAW,kBAAA;EHwf9C;AGvfmC;EAAW,kBAAA;EH0f9C;AGzfmC;EAAW,kBAAA;EH4f9C;AG3fmC;EAAW,kBAAA;EH8f9C;AG7fmC;EAAW,kBAAA;EHggB9C;AG/fmC;EAAW,kBAAA;EHkgB9C;AGjgBmC;EAAW,kBAAA;EHogB9C;AGngBmC;EAAW,kBAAA;EHsgB9C;AGrgBmC;EAAW,kBAAA;EHwgB9C;AGvgBmC;EAAW,kBAAA;EH0gB9C;AGzgBmC;EAAW,kBAAA;EH4gB9C;AG3gBmC;EAAW,kBAAA;EH8gB9C;AG7gBmC;EAAW,kBAAA;EHghB9C;AG/gBmC;EAAW,kBAAA;EHkhB9C;AGjhBmC;EAAW,kBAAA;EHohB9C;AGnhBmC;EAAW,kBAAA;EHshB9C;AGrhBmC;EAAW,kBAAA;EHwhB9C;AGvhBmC;EAAW,kBAAA;EH0hB9C;AGzhBmC;EAAW,kBAAA;EH4hB9C;AG3hBmC;EAAW,kBAAA;EH8hB9C;AG7hBmC;EAAW,kBAAA;EHgiB9C;AG/hBmC;EAAW,kBAAA;EHkiB9C;AGjiBmC;EAAW,kBAAA;EHoiB9C;AGniBmC;EAAW,kBAAA;EHsiB9C;AGriBmC;EAAW,kBAAA;EHwiB9C;AGviBmC;EAAW,kBAAA;EH0iB9C;AGziBmC;EAAW,kBAAA;EH4iB9C;AG3iBmC;EAAW,kBAAA;EH8iB9C;AG7iBmC;EAAW,kBAAA;EHgjB9C;AG/iBmC;EAAW,kBAAA;EHkjB9C;AGjjBmC;EAAW,kBAAA;EHojB9C;AGnjBmC;EAAW,kBAAA;EHsjB9C;AGrjBmC;EAAW,kBAAA;EHwjB9C;AGvjBmC;EAAW,kBAAA;EH0jB9C;AGzjBmC;EAAW,kBAAA;EH4jB9C;AG3jBmC;EAAW,kBAAA;EH8jB9C;AG7jBmC;EAAW,kBAAA;EHgkB9C;AG/jBmC;EAAW,kBAAA;EHkkB9C;AGjkBmC;EAAW,kBAAA;EHokB9C;AGnkBmC;EAAW,kBAAA;EHskB9C;AGrkBmC;EAAW,kBAAA;EHwkB9C;AGvkBmC;EAAW,kBAAA;EH0kB9C;AGzkBmC;EAAW,kBAAA;EH4kB9C;AG3kBmC;EAAW,kBAAA;EH8kB9C;AG7kBmC;EAAW,kBAAA;EHglB9C;AG/kBmC;EAAW,kBAAA;EHklB9C;AGjlBmC;EAAW,kBAAA;EHolB9C;AGnlBmC;EAAW,kBAAA;EHslB9C;AGrlBmC;EAAW,kBAAA;EHwlB9C;AGvlBmC;EAAW,kBAAA;EH0lB9C;AGzlBmC;EAAW,kBAAA;EH4lB9C;AG3lBmC;EAAW,kBAAA;EH8lB9C;AG7lBmC;EAAW,kBAAA;EHgmB9C;AG/lBmC;EAAW,kBAAA;EHkmB9C;AGjmBmC;EAAW,kBAAA;EHomB9C;AGnmBmC;EAAW,kBAAA;EHsmB9C;AGrmBmC;EAAW,kBAAA;EHwmB9C;AGvmBmC;EAAW,kBAAA;EH0mB9C;AGzmBmC;EAAW,kBAAA;EH4mB9C;AG3mBmC;EAAW,kBAAA;EH8mB9C;AG7mBmC;EAAW,kBAAA;EHgnB9C;AG/mBmC;EAAW,kBAAA;EHknB9C;AGjnBmC;EAAW,kBAAA;EHonB9C;AGnnBmC;EAAW,kBAAA;EHsnB9C;AGrnBmC;EAAW,kBAAA;EHwnB9C;AGvnBmC;EAAW,kBAAA;EH0nB9C;AGznBmC;EAAW,kBAAA;EH4nB9C;AG3nBmC;EAAW,kBAAA;EH8nB9C;AI71BD;ECgEE,gCAAA;EACG,6BAAA;EACK,wBAAA;ELgyBT;AI/1BD;;EC6DE,gCAAA;EACG,6BAAA;EACK,wBAAA;ELsyBT;AI71BD;EACE,iBAAA;EACA,+CAAA;EJ+1BD;AI51BD;EACE,6DAAA;EACA,iBAAA;EACA,yBAAA;EACA,gBAAA;EACA,2BAAA;EJ81BD;AI11BD;;;;EAIE,sBAAA;EACA,oBAAA;EACA,sBAAA;EJ41BD;AIt1BD;EACE,gBAAA;EACA,uBAAA;EJw1BD;AIt1BC;;EAEE,gBAAA;EACA,4BAAA;EJw1BH;AIr1BC;EErDA,sBAAA;EAEA,4CAAA;EACA,sBAAA;EN44BD;AI/0BD;EACE,WAAA;EJi1BD;AI30BD;EACE,wBAAA;EJ60BD;AIz0BD;;;;;EGvEE,gBAAA;EACA,iBAAA;EACA,cAAA;EPu5BD;AI70BD;EACE,oBAAA;EJ+0BD;AIz0BD;EACE,cAAA;EACA,yBAAA;EACA,2BAAA;EACA,2BAAA;EACA,oBAAA;EC6FA,0CAAA;EACK,qCAAA;EACG,kCAAA;EEvLR,uBAAA;EACA,iBAAA;EACA,cAAA;EPu6BD;AIz0BD;EACE,oBAAA;EJ20BD;AIr0BD;EACE,kBAAA;EACA,qBAAA;EACA,WAAA;EACA,+BAAA;EJu0BD;AI/zBD;EACE,oBAAA;EACA,YAAA;EACA,aAAA;EACA,cAAA;EACA,YAAA;EACA,kBAAA;EACA,wBAAA;EACA,WAAA;EJi0BD;AIzzBC;;EAEE,kBAAA;EACA,aAAA;EACA,cAAA;EACA,WAAA;EACA,mBAAA;EACA,YAAA;EJ2zBH;AQt8BD;;;;;;;;;;;;EAEE,sBAAA;EACA,kBAAA;EACA,kBAAA;EACA,gBAAA;ERk9BD;AQv9BD;;;;;;;;;;;;;;;;;;;;;;;;EASI,qBAAA;EACA,gBAAA;EACA,gBAAA;ERw+BH;AQp+BD;;;;;;EAGE,kBAAA;EACA,qBAAA;ERy+BD;AQ7+BD;;;;;;;;;;;;EAQI,gBAAA;ERm/BH;AQh/BD;;;;;;EAGE,kBAAA;EACA,qBAAA;ERq/BD;AQz/BD;;;;;;;;;;;;EAQI,gBAAA;ER+/BH;AQ3/BD;;EAAU,iBAAA;ER+/BT;AQ9/BD;;EAAU,iBAAA;ERkgCT;AQjgCD;;EAAU,iBAAA;ERqgCT;AQpgCD;;EAAU,iBAAA;ERwgCT;AQvgCD;;EAAU,iBAAA;ER2gCT;AQ1gCD;;EAAU,iBAAA;ER8gCT;AQxgCD;EACE,kBAAA;ER0gCD;AQvgCD;EACE,qBAAA;EACA,iBAAA;EACA,kBAAA;EACA,kBAAA;ERygCD;AQpgCD;EAAA;IAFI,iBAAA;IR0gCD;EACF;AQlgCD;;EAEE,gBAAA;ERogCD;AQjgCD;;EAEE,2BAAA;EACA,eAAA;ERmgCD;AQ//BD;EAAuB,kBAAA;ERkgCtB;AQjgCD;EAAuB,mBAAA;ERogCtB;AQngCD;EAAuB,oBAAA;ERsgCtB;AQrgCD;EAAuB,qBAAA;ERwgCtB;AQvgCD;EAAuB,qBAAA;ER0gCtB;AQvgCD;EAAuB,2BAAA;ER0gCtB;AQzgCD;EAAuB,2BAAA;ER4gCtB;AQ3gCD;EAAuB,4BAAA;ER8gCtB;AQ3gCD;EACE,gBAAA;ER6gCD;AQ3gCD;ECrGE,gBAAA;ETmnCD;ASlnCC;EACE,gBAAA;ETonCH;AQ9gCD;ECxGE,gBAAA;ETynCD;ASxnCC;EACE,gBAAA;ET0nCH;AQjhCD;EC3GE,gBAAA;ET+nCD;AS9nCC;EACE,gBAAA;ETgoCH;AQphCD;EC9GE,gBAAA;ETqoCD;ASpoCC;EACE,gBAAA;ETsoCH;AQvhCD;ECjHE,gBAAA;ET2oCD;AS1oCC;EACE,gBAAA;ET4oCH;AQthCD;EAGE,aAAA;EE3HA,2BAAA;EVkpCD;AUjpCC;EACE,2BAAA;EVmpCH;AQvhCD;EE9HE,2BAAA;EVwpCD;AUvpCC;EACE,2BAAA;EVypCH;AQ1hCD;EEjIE,2BAAA;EV8pCD;AU7pCC;EACE,2BAAA;EV+pCH;AQ7hCD;EEpIE,2BAAA;EVoqCD;AUnqCC;EACE,2BAAA;EVqqCH;AQhiCD;EEvIE,2BAAA;EV0qCD;AUzqCC;EACE,2BAAA;EV2qCH;AQ9hCD;EACE,qBAAA;EACA,qBAAA;EACA,kCAAA;ERgiCD;AQxhCD;;EAEE,eAAA;EACA,qBAAA;ER0hCD;AQ7hCD;;;;EAMI,kBAAA;ER6hCH;AQthCD;EACE,iBAAA;EACA,kBAAA;ERwhCD;AQphCD;EALE,iBAAA;EACA,kBAAA;EAMA,mBAAA;ERuhCD;AQzhCD;EAKI,uBAAA;EACA,mBAAA;EACA,oBAAA;ERuhCH;AQlhCD;EACE,eAAA;EACA,qBAAA;ERohCD;AQlhCD;;EAEE,yBAAA;ERohCD;AQlhCD;EACE,mBAAA;ERohCD;AQlhCD;EACE,gBAAA;ERohCD;AQ3/BD;EAAA;IAVM,aAAA;IACA,cAAA;IACA,aAAA;IACA,mBAAA;IGtNJ,kBAAA;IACA,yBAAA;IACA,qBAAA;IXguCC;EQrgCH;IAHM,oBAAA;IR2gCH;EACF;AQlgCD;;EAGE,cAAA;EACA,mCAAA;ERmgCD;AQjgCD;EACE,gBAAA;EACA,2BAAA;ERmgCD;AQ//BD;EACE,oBAAA;EACA,kBAAA;EACA,mBAAA;EACA,gCAAA;ERigCD;AQ5/BG;;;EACE,kBAAA;ERggCL;AQ1gCD;;;EAmBI,gBAAA;EACA,gBAAA;EACA,yBAAA;EACA,gBAAA;ER4/BH;AQ1/BG;;;EACE,wBAAA;ER8/BL;AQt/BD;;EAEE,qBAAA;EACA,iBAAA;EACA,iCAAA;EACA,gBAAA;EACA,mBAAA;ERw/BD;AQl/BG;;;;;;EAAW,aAAA;ER0/Bd;AQz/BG;;;;;;EACE,wBAAA;ERggCL;AQ1/BD;EACE,qBAAA;EACA,oBAAA;EACA,yBAAA;ER4/BD;AYlyCD;;;;EAIE,gEAAA;EZoyCD;AYhyCD;EACE,kBAAA;EACA,gBAAA;EACA,gBAAA;EACA,2BAAA;EACA,oBAAA;EZkyCD;AY9xCD;EACE,kBAAA;EACA,gBAAA;EACA,gBAAA;EACA,2BAAA;EACA,oBAAA;EACA,wDAAA;UAAA,gDAAA;EZgyCD;AYtyCD;EASI,YAAA;EACA,iBAAA;EACA,mBAAA;EACA,0BAAA;UAAA,kBAAA;EZgyCH;AY3xCD;EACE,gBAAA;EACA,gBAAA;EACA,kBAAA;EACA,iBAAA;EACA,yBAAA;EACA,uBAAA;EACA,uBAAA;EACA,gBAAA;EACA,2BAAA;EACA,2BAAA;EACA,oBAAA;EZ6xCD;AYxyCD;EAeI,YAAA;EACA,oBAAA;EACA,gBAAA;EACA,uBAAA;EACA,+BAAA;EACA,kBAAA;EZ4xCH;AYvxCD;EACE,mBAAA;EACA,oBAAA;EZyxCD;Aan1CD;ECHE,oBAAA;EACA,mBAAA;EACA,oBAAA;EACA,qBAAA;Edy1CD;Aan1CC;EAAA;IAFE,cAAA;Iby1CD;EACF;Aar1CC;EAAA;IAFE,cAAA;Ib21CD;EACF;Aav1CD;EAAA;IAFI,eAAA;Ib61CD;EACF;Aap1CD;ECvBE,oBAAA;EACA,mBAAA;EACA,oBAAA;EACA,qBAAA;Ed82CD;Aaj1CD;ECvBE,oBAAA;EACA,qBAAA;Ed22CD;Ae32CG;EACE,oBAAA;EAEA,iBAAA;EAEA,oBAAA;EACA,qBAAA;Ef22CL;Ae31CG;EACE,aAAA;Ef61CL;Aet1CC;EACE,aAAA;Efw1CH;Aez1CC;EACE,qBAAA;Ef21CH;Ae51CC;EACE,qBAAA;Ef81CH;Ae/1CC;EACE,YAAA;Efi2CH;Ael2CC;EACE,qBAAA;Efo2CH;Aer2CC;EACE,qBAAA;Efu2CH;Aex2CC;EACE,YAAA;Ef02CH;Ae32CC;EACE,qBAAA;Ef62CH;Ae92CC;EACE,qBAAA;Efg3CH;Aej3CC;EACE,YAAA;Efm3CH;Aep3CC;EACE,qBAAA;Efs3CH;Aev3CC;EACE,oBAAA;Efy3CH;Ae32CC;EACE,aAAA;Ef62CH;Ae92CC;EACE,qBAAA;Efg3CH;Aej3CC;EACE,qBAAA;Efm3CH;Aep3CC;EACE,YAAA;Efs3CH;Aev3CC;EACE,qBAAA;Efy3CH;Ae13CC;EACE,qBAAA;Ef43CH;Ae73CC;EACE,YAAA;Ef+3CH;Aeh4CC;EACE,qBAAA;Efk4CH;Aen4CC;EACE,qBAAA;Efq4CH;Aet4CC;EACE,YAAA;Efw4CH;Aez4CC;EACE,qBAAA;Ef24CH;Ae54CC;EACE,oBAAA;Ef84CH;Ae14CC;EACE,aAAA;Ef44CH;Ae55CC;EACE,YAAA;Ef85CH;Ae/5CC;EACE,oBAAA;Efi6CH;Ael6CC;EACE,oBAAA;Efo6CH;Aer6CC;EACE,WAAA;Efu6CH;Aex6CC;EACE,oBAAA;Ef06CH;Ae36CC;EACE,oBAAA;Ef66CH;Ae96CC;EACE,WAAA;Efg7CH;Aej7CC;EACE,oBAAA;Efm7CH;Aep7CC;EACE,oBAAA;Efs7CH;Aev7CC;EACE,WAAA;Efy7CH;Ae17CC;EACE,oBAAA;Ef47CH;Ae77CC;EACE,mBAAA;Ef+7CH;Ae37CC;EACE,YAAA;Ef67CH;Ae/6CC;EACE,mBAAA;Efi7CH;Ael7CC;EACE,2BAAA;Efo7CH;Aer7CC;EACE,2BAAA;Efu7CH;Aex7CC;EACE,kBAAA;Ef07CH;Ae37CC;EACE,2BAAA;Ef67CH;Ae97CC;EACE,2BAAA;Efg8CH;Aej8CC;EACE,kBAAA;Efm8CH;Aep8CC;EACE,2BAAA;Efs8CH;Aev8CC;EACE,2BAAA;Efy8CH;Ae18CC;EACE,kBAAA;Ef48CH;Ae78CC;EACE,2BAAA;Ef+8CH;Aeh9CC;EACE,0BAAA;Efk9CH;Aen9CC;EACE,iBAAA;Efq9CH;Aaz9CD;EE9BI;IACE,aAAA;If0/CH;Een/CD;IACE,aAAA;Ifq/CD;Eet/CD;IACE,qBAAA;Ifw/CD;Eez/CD;IACE,qBAAA;If2/CD;Ee5/CD;IACE,YAAA;If8/CD;Ee//CD;IACE,qBAAA;IfigDD;EelgDD;IACE,qBAAA;IfogDD;EergDD;IACE,YAAA;IfugDD;EexgDD;IACE,qBAAA;If0gDD;Ee3gDD;IACE,qBAAA;If6gDD;Ee9gDD;IACE,YAAA;IfghDD;EejhDD;IACE,qBAAA;IfmhDD;EephDD;IACE,oBAAA;IfshDD;EexgDD;IACE,aAAA;If0gDD;Ee3gDD;IACE,qBAAA;If6gDD;Ee9gDD;IACE,qBAAA;IfghDD;EejhDD;IACE,YAAA;IfmhDD;EephDD;IACE,qBAAA;IfshDD;EevhDD;IACE,qBAAA;IfyhDD;Ee1hDD;IACE,YAAA;If4hDD;Ee7hDD;IACE,qBAAA;If+hDD;EehiDD;IACE,qBAAA;IfkiDD;EeniDD;IACE,YAAA;IfqiDD;EetiDD;IACE,qBAAA;IfwiDD;EeziDD;IACE,oBAAA;If2iDD;EeviDD;IACE,aAAA;IfyiDD;EezjDD;IACE,YAAA;If2jDD;Ee5jDD;IACE,oBAAA;If8jDD;Ee/jDD;IACE,oBAAA;IfikDD;EelkDD;IACE,WAAA;IfokDD;EerkDD;IACE,oBAAA;IfukDD;EexkDD;IACE,oBAAA;If0kDD;Ee3kDD;IACE,WAAA;If6kDD;Ee9kDD;IACE,oBAAA;IfglDD;EejlDD;IACE,oBAAA;IfmlDD;EeplDD;IACE,WAAA;IfslDD;EevlDD;IACE,oBAAA;IfylDD;Ee1lDD;IACE,mBAAA;If4lDD;EexlDD;IACE,YAAA;If0lDD;Ee5kDD;IACE,mBAAA;If8kDD;Ee/kDD;IACE,2BAAA;IfilDD;EellDD;IACE,2BAAA;IfolDD;EerlDD;IACE,kBAAA;IfulDD;EexlDD;IACE,2BAAA;If0lDD;Ee3lDD;IACE,2BAAA;If6lDD;Ee9lDD;IACE,kBAAA;IfgmDD;EejmDD;IACE,2BAAA;IfmmDD;EepmDD;IACE,2BAAA;IfsmDD;EevmDD;IACE,kBAAA;IfymDD;Ee1mDD;IACE,2BAAA;If4mDD;Ee7mDD;IACE,0BAAA;If+mDD;EehnDD;IACE,iBAAA;IfknDD;EACF;Aa9mDD;EEvCI;IACE,aAAA;IfwpDH;EejpDD;IACE,aAAA;IfmpDD;EeppDD;IACE,qBAAA;IfspDD;EevpDD;IACE,qBAAA;IfypDD;Ee1pDD;IACE,YAAA;If4pDD;Ee7pDD;IACE,qBAAA;If+pDD;EehqDD;IACE,qBAAA;IfkqDD;EenqDD;IACE,YAAA;IfqqDD;EetqDD;IACE,qBAAA;IfwqDD;EezqDD;IACE,qBAAA;If2qDD;Ee5qDD;IACE,YAAA;If8qDD;Ee/qDD;IACE,qBAAA;IfirDD;EelrDD;IACE,oBAAA;IforDD;EetqDD;IACE,aAAA;IfwqDD;EezqDD;IACE,qBAAA;If2qDD;Ee5qDD;IACE,qBAAA;If8qDD;Ee/qDD;IACE,YAAA;IfirDD;EelrDD;IACE,qBAAA;IforDD;EerrDD;IACE,qBAAA;IfurDD;EexrDD;IACE,YAAA;If0rDD;Ee3rDD;IACE,qBAAA;If6rDD;Ee9rDD;IACE,qBAAA;IfgsDD;EejsDD;IACE,YAAA;IfmsDD;EepsDD;IACE,qBAAA;IfssDD;EevsDD;IACE,oBAAA;IfysDD;EersDD;IACE,aAAA;IfusDD;EevtDD;IACE,YAAA;IfytDD;Ee1tDD;IACE,oBAAA;If4tDD;Ee7tDD;IACE,oBAAA;If+tDD;EehuDD;IACE,WAAA;IfkuDD;EenuDD;IACE,oBAAA;IfquDD;EetuDD;IACE,oBAAA;IfwuDD;EezuDD;IACE,WAAA;If2uDD;Ee5uDD;IACE,oBAAA;If8uDD;Ee/uDD;IACE,oBAAA;IfivDD;EelvDD;IACE,WAAA;IfovDD;EervDD;IACE,oBAAA;IfuvDD;EexvDD;IACE,mBAAA;If0vDD;EetvDD;IACE,YAAA;IfwvDD;Ee1uDD;IACE,mBAAA;If4uDD;Ee7uDD;IACE,2BAAA;If+uDD;EehvDD;IACE,2BAAA;IfkvDD;EenvDD;IACE,kBAAA;IfqvDD;EetvDD;IACE,2BAAA;IfwvDD;EezvDD;IACE,2BAAA;If2vDD;Ee5vDD;IACE,kBAAA;If8vDD;Ee/vDD;IACE,2BAAA;IfiwDD;EelwDD;IACE,2BAAA;IfowDD;EerwDD;IACE,kBAAA;IfuwDD;EexwDD;IACE,2BAAA;If0wDD;Ee3wDD;IACE,0BAAA;If6wDD;Ee9wDD;IACE,iBAAA;IfgxDD;EACF;AarwDD;EE9CI;IACE,aAAA;IfszDH;Ee/yDD;IACE,aAAA;IfizDD;EelzDD;IACE,qBAAA;IfozDD;EerzDD;IACE,qBAAA;IfuzDD;EexzDD;IACE,YAAA;If0zDD;Ee3zDD;IACE,qBAAA;If6zDD;Ee9zDD;IACE,qBAAA;Ifg0DD;Eej0DD;IACE,YAAA;Ifm0DD;Eep0DD;IACE,qBAAA;Ifs0DD;Eev0DD;IACE,qBAAA;Ify0DD;Ee10DD;IACE,YAAA;If40DD;Ee70DD;IACE,qBAAA;If+0DD;Eeh1DD;IACE,oBAAA;Ifk1DD;Eep0DD;IACE,aAAA;Ifs0DD;Eev0DD;IACE,qBAAA;Ify0DD;Ee10DD;IACE,qBAAA;If40DD;Ee70DD;IACE,YAAA;If+0DD;Eeh1DD;IACE,qBAAA;Ifk1DD;Een1DD;IACE,qBAAA;Ifq1DD;Eet1DD;IACE,YAAA;Ifw1DD;Eez1DD;IACE,qBAAA;If21DD;Ee51DD;IACE,qBAAA;If81DD;Ee/1DD;IACE,YAAA;Ifi2DD;Eel2DD;IACE,qBAAA;Ifo2DD;Eer2DD;IACE,oBAAA;Ifu2DD;Een2DD;IACE,aAAA;Ifq2DD;Eer3DD;IACE,YAAA;Ifu3DD;Eex3DD;IACE,oBAAA;If03DD;Ee33DD;IACE,oBAAA;If63DD;Ee93DD;IACE,WAAA;Ifg4DD;Eej4DD;IACE,oBAAA;Ifm4DD;Eep4DD;IACE,oBAAA;Ifs4DD;Eev4DD;IACE,WAAA;Ify4DD;Ee14DD;IACE,oBAAA;If44DD;Ee74DD;IACE,oBAAA;If+4DD;Eeh5DD;IACE,WAAA;Ifk5DD;Een5DD;IACE,oBAAA;Ifq5DD;Eet5DD;IACE,mBAAA;Ifw5DD;Eep5DD;IACE,YAAA;Ifs5DD;Eex4DD;IACE,mBAAA;If04DD;Ee34DD;IACE,2BAAA;If64DD;Ee94DD;IACE,2BAAA;Ifg5DD;Eej5DD;IACE,kBAAA;Ifm5DD;Eep5DD;IACE,2BAAA;Ifs5DD;Eev5DD;IACE,2BAAA;Ify5DD;Ee15DD;IACE,kBAAA;If45DD;Ee75DD;IACE,2BAAA;If+5DD;Eeh6DD;IACE,2BAAA;Ifk6DD;Een6DD;IACE,kBAAA;Ifq6DD;Eet6DD;IACE,2BAAA;Ifw6DD;Eez6DD;IACE,0BAAA;If26DD;Ee56DD;IACE,iBAAA;If86DD;EACF;AgBl/DD;EACE,+BAAA;EhBo/DD;AgBl/DD;EACE,kBAAA;EACA,qBAAA;EACA,gBAAA;EACA,kBAAA;EhBo/DD;AgBl/DD;EACE,kBAAA;EhBo/DD;AgB9+DD;EACE,aAAA;EACA,iBAAA;EACA,qBAAA;EhBg/DD;AgBn/DD;;;;;;EAWQ,cAAA;EACA,yBAAA;EACA,qBAAA;EACA,+BAAA;EhBg/DP;AgB9/DD;EAoBI,wBAAA;EACA,kCAAA;EhB6+DH;AgBlgED;;;;;;EA8BQ,eAAA;EhB4+DP;AgB1gED;EAoCI,+BAAA;EhBy+DH;AgB7gED;EAyCI,2BAAA;EhBu+DH;AgBh+DD;;;;;;EAOQ,cAAA;EhBi+DP;AgBt9DD;EACE,2BAAA;EhBw9DD;AgBz9DD;;;;;;EAQQ,2BAAA;EhBy9DP;AgBj+DD;;EAeM,0BAAA;EhBs9DL;AgB58DD;EAEI,2BAAA;EhB68DH;AgBp8DD;EAEI,2BAAA;EhBq8DH;AgB57DD;EACE,kBAAA;EACA,aAAA;EACA,uBAAA;EhB87DD;AgBz7DG;;EACE,kBAAA;EACA,aAAA;EACA,qBAAA;EhB47DL;AiBxkEC;;;;;;;;;;;;EAOI,2BAAA;EjB+kEL;AiBzkEC;;;;;EAMI,2BAAA;EjB0kEL;AiB7lEC;;;;;;;;;;;;EAOI,2BAAA;EjBomEL;AiB9lEC;;;;;EAMI,2BAAA;EjB+lEL;AiBlnEC;;;;;;;;;;;;EAOI,2BAAA;EjBynEL;AiBnnEC;;;;;EAMI,2BAAA;EjBonEL;AiBvoEC;;;;;;;;;;;;EAOI,2BAAA;EjB8oEL;AiBxoEC;;;;;EAMI,2BAAA;EjByoEL;AiB5pEC;;;;;;;;;;;;EAOI,2BAAA;EjBmqEL;AiB7pEC;;;;;EAMI,2BAAA;EjB8pEL;AgB5gED;EACE,kBAAA;EACA,mBAAA;EhB8gED;AgBj9DD;EAAA;IA1DI,aAAA;IACA,qBAAA;IACA,oBAAA;IACA,8CAAA;IACA,2BAAA;IhB+gED;EgBz9DH;IAlDM,kBAAA;IhB8gEH;EgB59DH;;;;;;IAzCY,qBAAA;IhB6gET;EgBp+DH;IAjCM,WAAA;IhBwgEH;EgBv+DH;;;;;;IAxBY,gBAAA;IhBugET;EgB/+DH;;;;;;IApBY,iBAAA;IhB2gET;EgBv/DH;;;;IAPY,kBAAA;IhBogET;EACF;AkB9tED;EACE,YAAA;EACA,WAAA;EACA,WAAA;EAIA,cAAA;ElB6tED;AkB1tED;EACE,gBAAA;EACA,aAAA;EACA,YAAA;EACA,qBAAA;EACA,iBAAA;EACA,sBAAA;EACA,gBAAA;EACA,WAAA;EACA,kCAAA;ElB4tED;AkBztED;EACE,uBAAA;EACA,iBAAA;EACA,oBAAA;EACA,mBAAA;ElB2tED;AkBhtED;Eb4BE,gCAAA;EACG,6BAAA;EACK,wBAAA;ELurET;AkBhtED;;EAEE,iBAAA;EACA,oBAAA;EACA,qBAAA;ElBktED;AkB9sED;EACE,gBAAA;ElBgtED;AkB5sED;EACE,gBAAA;EACA,aAAA;ElB8sED;AkB1sED;;EAEE,cAAA;ElB4sED;AkBxsED;;;EZxEE,sBAAA;EAEA,4CAAA;EACA,sBAAA;ENoxED;AkBxsED;EACE,gBAAA;EACA,kBAAA;EACA,iBAAA;EACA,yBAAA;EACA,gBAAA;ElB0sED;AkBhrED;EACE,gBAAA;EACA,aAAA;EACA,cAAA;EACA,mBAAA;EACA,iBAAA;EACA,yBAAA;EACA,gBAAA;EACA,2BAAA;EACA,wBAAA;EACA,2BAAA;EACA,oBAAA;EbzDA,0DAAA;EACQ,kDAAA;EAyHR,wFAAA;EACK,2EAAA;EACG,wEAAA;ELonET;AmB5vEC;EACE,uBAAA;EACA,YAAA;EdUF,wFAAA;EACQ,gFAAA;ELqvET;AKptEC;EACE,gBAAA;EACA,YAAA;ELstEH;AKptEC;EAA0B,gBAAA;ELutE3B;AKttEC;EAAgC,gBAAA;ELytEjC;AkBxrEC;;;EAGE,qBAAA;EACA,2BAAA;EACA,YAAA;ElB0rEH;AkBtrEC;EACE,cAAA;ElBwrEH;AkB5qED;EACE,0BAAA;ElB8qED;AkB7oED;EArBE;;;;IAIE,mBAAA;IlBqqED;EkBnqED;;;;IAIE,mBAAA;IlBqqED;EkBnqED;;;;IAIE,mBAAA;IlBqqED;EACF;AkB5pED;EACE,qBAAA;ElB8pED;AkBtpED;;EAEE,oBAAA;EACA,gBAAA;EACA,kBAAA;EACA,qBAAA;ElBwpED;AkB7pED;;EAQI,kBAAA;EACA,oBAAA;EACA,kBAAA;EACA,qBAAA;EACA,iBAAA;ElBypEH;AkBtpED;;;;EAIE,oBAAA;EACA,oBAAA;EACA,oBAAA;ElBwpED;AkBrpED;;EAEE,kBAAA;ElBupED;AkBnpED;;EAEE,uBAAA;EACA,oBAAA;EACA,kBAAA;EACA,wBAAA;EACA,qBAAA;EACA,iBAAA;ElBqpED;AkBnpED;;EAEE,eAAA;EACA,mBAAA;ElBqpED;AkB5oEC;;;;;;EAGE,qBAAA;ElBipEH;AkB3oEC;;;;EAEE,qBAAA;ElB+oEH;AkBzoEC;;;;EAGI,qBAAA;ElB4oEL;AkBjoED;EAEE,kBAAA;EACA,qBAAA;EAEA,kBAAA;ElBioED;AkB/nEC;;EAEE,iBAAA;EACA,kBAAA;ElBioEH;AkBvnED;;ECnPE,cAAA;EACA,mBAAA;EACA,iBAAA;EACA,kBAAA;EACA,oBAAA;EnB82ED;AmB52EC;;EACE,cAAA;EACA,mBAAA;EnB+2EH;AmB52EC;;;;EAEE,cAAA;EnBg3EH;AkBroED;;ECxPE,cAAA;EACA,oBAAA;EACA,iBAAA;EACA,mBAAA;EACA,oBAAA;EnBi4ED;AmB/3EC;;EACE,cAAA;EACA,mBAAA;EnBk4EH;AmB/3EC;;;;EAEE,cAAA;EnBm4EH;AkB9oED;EAEE,oBAAA;ElB+oED;AkBjpED;EAMI,uBAAA;ElB8oEH;AkB1oED;EACE,oBAAA;EACA,QAAA;EACA,UAAA;EACA,YAAA;EACA,gBAAA;EACA,aAAA;EACA,cAAA;EACA,mBAAA;EACA,oBAAA;EACA,sBAAA;ElB4oED;AkB1oED;EACE,aAAA;EACA,cAAA;EACA,mBAAA;ElB4oED;AkB1oED;EACE,aAAA;EACA,cAAA;EACA,mBAAA;ElB4oED;AkBxoED;;;;;;;;;;ECxVI,gBAAA;EnB4+EH;AkBppED;ECpVI,uBAAA;Ed+CF,0DAAA;EACQ,kDAAA;EL67ET;AmB3+EG;EACE,uBAAA;Ed4CJ,2EAAA;EACQ,mEAAA;ELk8ET;AkB9pED;EC1UI,gBAAA;EACA,uBAAA;EACA,2BAAA;EnB2+EH;AkBnqED;ECpUI,gBAAA;EnB0+EH;AkBnqED;;;;;;;;;;EC3VI,gBAAA;EnB0gFH;AkB/qED;ECvVI,uBAAA;Ed+CF,0DAAA;EACQ,kDAAA;EL29ET;AmBzgFG;EACE,uBAAA;Ed4CJ,2EAAA;EACQ,mEAAA;ELg+ET;AkBzrED;EC7UI,gBAAA;EACA,uBAAA;EACA,2BAAA;EnBygFH;AkB9rED;ECvUI,gBAAA;EnBwgFH;AkB9rED;;;;;;;;;;EC9VI,gBAAA;EnBwiFH;AkB1sED;EC1VI,uBAAA;Ed+CF,0DAAA;EACQ,kDAAA;ELy/ET;AmBviFG;EACE,uBAAA;Ed4CJ,2EAAA;EACQ,mEAAA;EL8/ET;AkBptED;EChVI,gBAAA;EACA,uBAAA;EACA,2BAAA;EnBuiFH;AkBztED;EC1UI,gBAAA;EnBsiFH;AkBrtEC;EACG,WAAA;ElButEJ;AkBrtEC;EACG,QAAA;ElButEJ;AkB7sED;EACE,gBAAA;EACA,iBAAA;EACA,qBAAA;EACA,gBAAA;ElB+sED;AkB3nED;EAAA;IA/DM,uBAAA;IACA,kBAAA;IACA,wBAAA;IlB8rEH;EkBjoEH;IAxDM,uBAAA;IACA,aAAA;IACA,wBAAA;IlB4rEH;EkBtoEH;IAjDM,uBAAA;IlB0rEH;EkBzoEH;IA7CM,uBAAA;IACA,wBAAA;IlByrEH;EkB7oEH;;;IAvCQ,aAAA;IlByrEL;EkBlpEH;IAjCM,aAAA;IlBsrEH;EkBrpEH;IA7BM,kBAAA;IACA,wBAAA;IlBqrEH;EkBzpEH;;IApBM,uBAAA;IACA,eAAA;IACA,kBAAA;IACA,wBAAA;IlBirEH;EkBhqEH;;IAdQ,iBAAA;IlBkrEL;EkBpqEH;;IATM,oBAAA;IACA,gBAAA;IlBirEH;EkBzqEH;IAHM,QAAA;IlB+qEH;EACF;AkBrqED;;;;EASI,eAAA;EACA,kBAAA;EACA,kBAAA;ElBkqEH;AkB7qED;;EAiBI,kBAAA;ElBgqEH;AkBjrED;EJrdE,oBAAA;EACA,qBAAA;EdyoFD;AkBlpEC;EAAA;IANI,mBAAA;IACA,kBAAA;IACA,kBAAA;IlB4pEH;EACF;AkB5rED;EAwCI,aAAA;ElBupEH;AkB1oEC;EAAA;IAHM,qBAAA;IlBipEL;EACF;AkBxoEC;EAAA;IAHM,kBAAA;IlB+oEL;EACF;AoBrqFD;EACE,uBAAA;EACA,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,wBAAA;EACA,gCAAA;MAAA,4BAAA;EACA,iBAAA;EACA,wBAAA;EACA,+BAAA;EACA,qBAAA;EC6BA,mBAAA;EACA,iBAAA;EACA,yBAAA;EACA,oBAAA;EhB4KA,2BAAA;EACG,wBAAA;EACC,uBAAA;EACI,mBAAA;ELg+ET;AoBxqFG;;;;;;EdrBF,sBAAA;EAEA,4CAAA;EACA,sBAAA;ENosFD;AoB5qFC;;;EAGE,gBAAA;EACA,uBAAA;EpB8qFH;AoB3qFC;;EAEE,YAAA;EACA,wBAAA;Ef2BF,0DAAA;EACQ,kDAAA;ELmpFT;AoB3qFC;;;EAGE,qBAAA;EACA,sBAAA;EE9CF,eAAA;EAGA,2BAAA;EjB8DA,0BAAA;EACQ,kBAAA;EL6pFT;AoBvqFD;ECrDE,gBAAA;EACA,2BAAA;EACA,uBAAA;ErB+tFD;AqB7tFC;;;;;;EAME,gBAAA;EACA,2BAAA;EACI,uBAAA;ErB+tFP;AqB7tFC;;;EAGE,wBAAA;ErB+tFH;AqB1tFG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACI,uBAAA;ErBwuFT;AoBhtFD;ECnBI,gBAAA;EACA,2BAAA;ErBsuFH;AoBjtFD;ECxDE,gBAAA;EACA,2BAAA;EACA,uBAAA;ErB4wFD;AqB1wFC;;;;;;EAME,gBAAA;EACA,2BAAA;EACI,uBAAA;ErB4wFP;AqB1wFC;;;EAGE,wBAAA;ErB4wFH;AqBvwFG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACI,uBAAA;ErBqxFT;AoB1vFD;ECtBI,gBAAA;EACA,2BAAA;ErBmxFH;AoB1vFD;EC5DE,gBAAA;EACA,2BAAA;EACA,uBAAA;ErByzFD;AqBvzFC;;;;;;EAME,gBAAA;EACA,2BAAA;EACI,uBAAA;ErByzFP;AqBvzFC;;;EAGE,wBAAA;ErByzFH;AqBpzFG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACI,uBAAA;ErBk0FT;AoBnyFD;EC1BI,gBAAA;EACA,2BAAA;ErBg0FH;AoBnyFD;EChEE,gBAAA;EACA,2BAAA;EACA,uBAAA;ErBs2FD;AqBp2FC;;;;;;EAME,gBAAA;EACA,2BAAA;EACI,uBAAA;ErBs2FP;AqBp2FC;;;EAGE,wBAAA;ErBs2FH;AqBj2FG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACI,uBAAA;ErB+2FT;AoB50FD;EC9BI,gBAAA;EACA,2BAAA;ErB62FH;AoB50FD;ECpEE,gBAAA;EACA,2BAAA;EACA,uBAAA;ErBm5FD;AqBj5FC;;;;;;EAME,gBAAA;EACA,2BAAA;EACI,uBAAA;ErBm5FP;AqBj5FC;;;EAGE,wBAAA;ErBm5FH;AqB94FG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACI,uBAAA;ErB45FT;AoBr3FD;EClCI,gBAAA;EACA,2BAAA;ErB05FH;AoBr3FD;ECxEE,gBAAA;EACA,2BAAA;EACA,uBAAA;ErBg8FD;AqB97FC;;;;;;EAME,gBAAA;EACA,2BAAA;EACI,uBAAA;ErBg8FP;AqB97FC;;;EAGE,wBAAA;ErBg8FH;AqB37FG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACI,uBAAA;ErBy8FT;AoB95FD;ECtCI,gBAAA;EACA,2BAAA;ErBu8FH;AoBz5FD;EACE,gBAAA;EACA,qBAAA;EACA,kBAAA;EpB25FD;AoBz5FC;;;;;EAKE,+BAAA;Ef7BF,0BAAA;EACQ,kBAAA;ELy7FT;AoB15FC;;;;EAIE,2BAAA;EpB45FH;AoB15FC;;EAEE,gBAAA;EACA,4BAAA;EACA,+BAAA;EpB45FH;AoBx5FG;;;;EAEE,gBAAA;EACA,uBAAA;EpB45FL;AoBn5FD;;EC/EE,oBAAA;EACA,iBAAA;EACA,mBAAA;EACA,oBAAA;ErBs+FD;AoBt5FD;;ECnFE,mBAAA;EACA,iBAAA;EACA,kBAAA;EACA,oBAAA;ErB6+FD;AoBz5FD;;ECvFE,kBAAA;EACA,iBAAA;EACA,kBAAA;EACA,oBAAA;ErBo/FD;AoBx5FD;EACE,gBAAA;EACA,aAAA;EpB05FD;AoBt5FD;EACE,iBAAA;EpBw5FD;AoBj5FC;;;EACE,aAAA;EpBq5FH;AuBziGD;EACE,YAAA;ElBoLA,0CAAA;EACK,qCAAA;EACG,kCAAA;ELw3FT;AuB5iGC;EACE,YAAA;EvB8iGH;AuB1iGD;EACE,eAAA;EACA,oBAAA;EvB4iGD;AuB1iGC;EAAY,gBAAA;EAAgB,qBAAA;EvB8iG7B;AuB7iGC;EAAY,oBAAA;EvBgjGb;AuB/iGC;EAAY,0BAAA;EvBkjGb;AuB/iGD;EACE,oBAAA;EACA,WAAA;EACA,kBAAA;ElBsKA,iDAAA;EACQ,4CAAA;KAAA,yCAAA;EAOR,oCAAA;EACQ,+BAAA;KAAA,4BAAA;EAGR,0CAAA;EACQ,qCAAA;KAAA,kCAAA;ELo4FT;AwB9kGD;EACE,uBAAA;EACA,UAAA;EACA,WAAA;EACA,kBAAA;EACA,wBAAA;EACA,uBAAA;EACA,qCAAA;EACA,oCAAA;ExBglGD;AwB5kGD;EACE,oBAAA;ExB8kGD;AwB1kGD;EACE,YAAA;ExB4kGD;AwBxkGD;EACE,oBAAA;EACA,WAAA;EACA,SAAA;EACA,eAAA;EACA,eAAA;EACA,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,kBAAA;EACA,iBAAA;EACA,kBAAA;EACA,2BAAA;EACA,2BAAA;EACA,uCAAA;EACA,oBAAA;EnBwBA,qDAAA;EACQ,6CAAA;EmBvBR,sCAAA;UAAA,8BAAA;ExB2kGD;AwBtkGC;EACE,UAAA;EACA,YAAA;ExBwkGH;AwBjmGD;ECvBE,aAAA;EACA,eAAA;EACA,kBAAA;EACA,2BAAA;EzB2nGD;AwBvmGD;EAmCI,gBAAA;EACA,mBAAA;EACA,aAAA;EACA,qBAAA;EACA,yBAAA;EACA,gBAAA;EACA,qBAAA;ExBukGH;AwBjkGC;;EAEE,uBAAA;EACA,gBAAA;EACA,2BAAA;ExBmkGH;AwB7jGC;;;EAGE,gBAAA;EACA,uBAAA;EACA,YAAA;EACA,2BAAA;ExB+jGH;AwBtjGC;;;EAGE,gBAAA;ExBwjGH;AwBpjGC;;EAEE,uBAAA;EACA,+BAAA;EACA,wBAAA;EEzGF,qEAAA;EF2GE,qBAAA;ExBsjGH;AwBjjGD;EAGI,gBAAA;ExBijGH;AwBpjGD;EAQI,YAAA;ExB+iGH;AwBviGD;EACE,YAAA;EACA,UAAA;ExByiGD;AwBjiGD;EACE,SAAA;EACA,aAAA;ExBmiGD;AwB/hGD;EACE,gBAAA;EACA,mBAAA;EACA,iBAAA;EACA,yBAAA;EACA,gBAAA;EACA,qBAAA;ExBiiGD;AwB7hGD;EACE,iBAAA;EACA,SAAA;EACA,UAAA;EACA,WAAA;EACA,QAAA;EACA,cAAA;ExB+hGD;AwB3hGD;EACE,UAAA;EACA,YAAA;ExB6hGD;AwBrhGD;;EAII,eAAA;EACA,0BAAA;EACA,aAAA;ExBqhGH;AwB3hGD;;EAUI,WAAA;EACA,cAAA;EACA,oBAAA;ExBqhGH;AwBhgGD;EAXE;IAnEA,YAAA;IACA,UAAA;IxBklGC;EwBhhGD;IAzDA,SAAA;IACA,aAAA;IxB4kGC;EACF;A2B1tGD;;EAEE,oBAAA;EACA,uBAAA;EACA,wBAAA;E3B4tGD;A2BhuGD;;EAMI,oBAAA;EACA,aAAA;E3B8tGH;A2B5tGG;;;;;;;;EAIE,YAAA;E3BkuGL;A2B5tGD;;;;EAKI,mBAAA;E3B6tGH;A2BxtGD;EACE,mBAAA;E3B0tGD;A2B3tGD;;EAMI,aAAA;E3BytGH;A2B/tGD;;;EAWI,kBAAA;E3BytGH;A2BrtGD;EACE,kBAAA;E3ButGD;A2BntGD;EACE,gBAAA;E3BqtGD;A2BptGC;ECjDA,+BAAA;EACG,4BAAA;E5BwwGJ;A2BntGD;;EC9CE,8BAAA;EACG,2BAAA;E5BqwGJ;A2BltGD;EACE,aAAA;E3BotGD;A2BltGD;EACE,kBAAA;E3BotGD;A2BltGD;;EClEE,+BAAA;EACG,4BAAA;E5BwxGJ;A2BjtGD;EChEE,8BAAA;EACG,2BAAA;E5BoxGJ;A2BhtGD;;EAEE,YAAA;E3BktGD;A2BjsGD;EACE,mBAAA;EACA,oBAAA;E3BmsGD;A2BjsGD;EACE,oBAAA;EACA,qBAAA;E3BmsGD;A2B9rGD;EtB9CE,0DAAA;EACQ,kDAAA;EL+uGT;A2B9rGC;EtBlDA,0BAAA;EACQ,kBAAA;ELmvGT;A2B3rGD;EACE,gBAAA;E3B6rGD;A2B1rGD;EACE,yBAAA;EACA,wBAAA;E3B4rGD;A2BzrGD;EACE,yBAAA;E3B2rGD;A2BprGD;;;EAII,gBAAA;EACA,aAAA;EACA,aAAA;EACA,iBAAA;E3BqrGH;A2B5rGD;EAcM,aAAA;E3BirGL;A2B/rGD;;;;EAsBI,kBAAA;EACA,gBAAA;E3B+qGH;A2B1qGC;EACE,kBAAA;E3B4qGH;A2B1qGC;EACE,8BAAA;ECnKF,+BAAA;EACC,8BAAA;E5Bg1GF;A2B3qGC;EACE,gCAAA;EC/KF,4BAAA;EACC,2BAAA;E5B61GF;A2B3qGD;EACE,kBAAA;E3B6qGD;A2B3qGD;;EC9KE,+BAAA;EACC,8BAAA;E5B61GF;A2B1qGD;EC5LE,4BAAA;EACC,2BAAA;E5By2GF;A2BtqGD;EACE,gBAAA;EACA,aAAA;EACA,qBAAA;EACA,2BAAA;E3BwqGD;A2B5qGD;;EAOI,aAAA;EACA,qBAAA;EACA,WAAA;E3ByqGH;A2BlrGD;EAYI,aAAA;E3ByqGH;A2BrrGD;EAgBI,YAAA;E3BwqGH;A2BvpGD;;;;EAKM,oBAAA;EACA,wBAAA;EACA,sBAAA;E3BwpGL;A6Bj4GD;EACE,oBAAA;EACA,gBAAA;EACA,2BAAA;E7Bm4GD;A6Bh4GC;EACE,aAAA;EACA,iBAAA;EACA,kBAAA;E7Bk4GH;A6B34GD;EAeI,oBAAA;EACA,YAAA;EAKA,aAAA;EAEA,aAAA;EACA,kBAAA;E7B03GH;A6Bj3GD;;;EV8BE,cAAA;EACA,oBAAA;EACA,iBAAA;EACA,mBAAA;EACA,oBAAA;EnBw1GD;AmBt1GC;;;EACE,cAAA;EACA,mBAAA;EnB01GH;AmBv1GC;;;;;;EAEE,cAAA;EnB61GH;A6Bn4GD;;;EVyBE,cAAA;EACA,mBAAA;EACA,iBAAA;EACA,kBAAA;EACA,oBAAA;EnB+2GD;AmB72GC;;;EACE,cAAA;EACA,mBAAA;EnBi3GH;AmB92GC;;;;;;EAEE,cAAA;EnBo3GH;A6Bj5GD;;;EAGE,qBAAA;E7Bm5GD;A6Bj5GC;;;EACE,kBAAA;E7Bq5GH;A6Bj5GD;;EAEE,WAAA;EACA,qBAAA;EACA,wBAAA;E7Bm5GD;A6B94GD;EACE,mBAAA;EACA,iBAAA;EACA,qBAAA;EACA,gBAAA;EACA,gBAAA;EACA,oBAAA;EACA,2BAAA;EACA,2BAAA;EACA,oBAAA;E7Bg5GD;A6B74GC;EACE,mBAAA;EACA,iBAAA;EACA,oBAAA;E7B+4GH;A6B74GC;EACE,oBAAA;EACA,iBAAA;EACA,oBAAA;E7B+4GH;A6Bn6GD;;EA0BI,eAAA;E7B64GH;A6Bx4GD;;;;;;;EDhGE,+BAAA;EACG,4BAAA;E5Bi/GJ;A6Bz4GD;EACE,iBAAA;E7B24GD;A6Bz4GD;;;;;;;EDpGE,8BAAA;EACG,2BAAA;E5Bs/GJ;A6B14GD;EACE,gBAAA;E7B44GD;A6Bv4GD;EACE,oBAAA;EAGA,cAAA;EACA,qBAAA;E7Bu4GD;A6B54GD;EAUI,oBAAA;E7Bq4GH;A6B/4GD;EAYM,mBAAA;E7Bs4GL;A6Bn4GG;;;EAGE,YAAA;E7Bq4GL;A6Bh4GC;;EAGI,oBAAA;E7Bi4GL;A6B93GC;;EAGI,mBAAA;E7B+3GL;A8BzhHD;EACE,kBAAA;EACA,iBAAA;EACA,kBAAA;E9B2hHD;A8B9hHD;EAOI,oBAAA;EACA,gBAAA;E9B0hHH;A8BliHD;EAWM,oBAAA;EACA,gBAAA;EACA,oBAAA;E9B0hHL;A8BzhHK;;EAEE,uBAAA;EACA,2BAAA;E9B2hHP;A8BthHG;EACE,gBAAA;E9BwhHL;A8BthHK;;EAEE,gBAAA;EACA,uBAAA;EACA,+BAAA;EACA,qBAAA;E9BwhHP;A8BjhHG;;;EAGE,2BAAA;EACA,uBAAA;E9BmhHL;A8B5jHD;ELHE,aAAA;EACA,eAAA;EACA,kBAAA;EACA,2BAAA;EzBkkHD;A8BlkHD;EA0DI,iBAAA;E9B2gHH;A8BlgHD;EACE,kCAAA;E9BogHD;A8BrgHD;EAGI,aAAA;EAEA,qBAAA;E9BogHH;A8BzgHD;EASM,mBAAA;EACA,yBAAA;EACA,+BAAA;EACA,4BAAA;E9BmgHL;A8BlgHK;EACE,uCAAA;E9BogHP;A8B9/GK;;;EAGE,gBAAA;EACA,2BAAA;EACA,2BAAA;EACA,kCAAA;EACA,iBAAA;E9BggHP;A8B3/GC;EAqDA,aAAA;EA8BA,kBAAA;E9B46GD;A8B//GC;EAwDE,aAAA;E9B08GH;A8BlgHC;EA0DI,oBAAA;EACA,oBAAA;E9B28GL;A8BtgHC;EAgEE,WAAA;EACA,YAAA;E9By8GH;A8B77GD;EAAA;IAPM,qBAAA;IACA,WAAA;I9Bw8GH;E8Bl8GH;IAJQ,kBAAA;I9By8GL;EACF;A8BnhHC;EAuFE,iBAAA;EACA,oBAAA;E9B+7GH;A8BvhHC;;;EA8FE,2BAAA;E9B87GH;A8Bh7GD;EAAA;IATM,kCAAA;IACA,4BAAA;I9B67GH;E8Br7GH;;;IAHM,8BAAA;I9B67GH;EACF;A8B9hHD;EAEI,aAAA;E9B+hHH;A8BjiHD;EAMM,oBAAA;E9B8hHL;A8BpiHD;EASM,kBAAA;E9B8hHL;A8BzhHK;;;EAGE,gBAAA;EACA,2BAAA;E9B2hHP;A8BnhHD;EAEI,aAAA;E9BohHH;A8BthHD;EAIM,iBAAA;EACA,gBAAA;E9BqhHL;A8BzgHD;EACE,aAAA;E9B2gHD;A8B5gHD;EAII,aAAA;E9B2gHH;A8B/gHD;EAMM,oBAAA;EACA,oBAAA;E9B4gHL;A8BnhHD;EAYI,WAAA;EACA,YAAA;E9B0gHH;A8B9/GD;EAAA;IAPM,qBAAA;IACA,WAAA;I9BygHH;E8BngHH;IAJQ,kBAAA;I9B0gHL;EACF;A8BlgHD;EACE,kBAAA;E9BogHD;A8BrgHD;EAKI,iBAAA;EACA,oBAAA;E9BmgHH;A8BzgHD;;;EAYI,2BAAA;E9BkgHH;A8Bp/GD;EAAA;IATM,kCAAA;IACA,4BAAA;I9BigHH;E8Bz/GH;;;IAHM,8BAAA;I9BigHH;EACF;A8Bx/GD;EAEI,eAAA;EACA,oBAAA;E9By/GH;A8B5/GD;EAMI,gBAAA;EACA,qBAAA;E9By/GH;A8Bh/GD;EAEE,kBAAA;EF7OA,4BAAA;EACC,2BAAA;E5B+tHF;A+BztHD;EACE,oBAAA;EACA,kBAAA;EACA,qBAAA;EACA,+BAAA;E/B2tHD;A+BntHD;EAAA;IAFI,oBAAA;I/BytHD;EACF;A+B1sHD;EAAA;IAFI,aAAA;I/BgtHD;EACF;A+BlsHD;EACE,qBAAA;EACA,qBAAA;EACA,oBAAA;EACA,mCAAA;EACA,4DAAA;UAAA,oDAAA;EAEA,mCAAA;E/BmsHD;A+BjsHC;EACE,kBAAA;E/BmsHH;A+BtqHD;EAAA;IAzBI,aAAA;IACA,eAAA;IACA,0BAAA;YAAA,kBAAA;I/BmsHD;E+BjsHC;IACE,2BAAA;IACA,gCAAA;IACA,yBAAA;IACA,mBAAA;IACA,8BAAA;I/BmsHH;E+BhsHC;IACE,qBAAA;I/BksHH;E+B7rHC;;;IAGE,iBAAA;IACA,kBAAA;I/B+rHH;EACF;A+B3rHD;;EAGI,mBAAA;E/B4rHH;A+BvrHC;EAAA;;IAFI,mBAAA;I/B8rHH;EACF;A+BrrHD;;;;EAII,qBAAA;EACA,oBAAA;E/BurHH;A+BjrHC;EAAA;;;;IAHI,iBAAA;IACA,gBAAA;I/B2rHH;EACF;A+B/qHD;EACE,eAAA;EACA,uBAAA;E/BirHD;A+B5qHD;EAAA;IAFI,kBAAA;I/BkrHD;EACF;A+B9qHD;;EAEE,iBAAA;EACA,UAAA;EACA,SAAA;EACA,eAAA;E/BgrHD;A+B1qHD;EAAA;;IAFI,kBAAA;I/BirHD;EACF;A+B/qHD;EACE,QAAA;EACA,uBAAA;E/BirHD;A+B/qHD;EACE,WAAA;EACA,kBAAA;EACA,uBAAA;E/BirHD;A+B3qHD;EACE,aAAA;EACA,oBAAA;EACA,iBAAA;EACA,mBAAA;EACA,cAAA;E/B6qHD;A+B3qHC;;EAEE,uBAAA;E/B6qHH;A+BtrHD;EAaI,gBAAA;E/B4qHH;A+BnqHD;EALI;;IAEE,oBAAA;I/B2qHH;EACF;A+BjqHD;EACE,oBAAA;EACA,cAAA;EACA,oBAAA;EACA,mBAAA;EC/LA,iBAAA;EACA,oBAAA;EDgMA,+BAAA;EACA,wBAAA;EACA,+BAAA;EACA,oBAAA;E/BoqHD;A+BhqHC;EACE,YAAA;E/BkqHH;A+BhrHD;EAmBI,gBAAA;EACA,aAAA;EACA,aAAA;EACA,oBAAA;E/BgqHH;A+BtrHD;EAyBI,iBAAA;E/BgqHH;A+B1pHD;EAAA;IAFI,eAAA;I/BgqHD;EACF;A+BvpHD;EACE,qBAAA;E/BypHD;A+B1pHD;EAII,mBAAA;EACA,sBAAA;EACA,mBAAA;E/BypHH;A+B9nHC;EAAA;IArBI,kBAAA;IACA,aAAA;IACA,aAAA;IACA,eAAA;IACA,+BAAA;IACA,WAAA;IACA,0BAAA;YAAA,kBAAA;I/BupHH;E+BxoHD;;IAZM,4BAAA;I/BwpHL;E+B5oHD;IATM,mBAAA;I/BwpHL;E+BvpHK;;IAEE,wBAAA;I/BypHP;EACF;A+BvoHD;EAAA;IAXI,aAAA;IACA,WAAA;I/BspHD;E+B5oHH;IAPM,aAAA;I/BspHH;E+B/oHH;IALQ,mBAAA;IACA,sBAAA;I/BupHL;EACF;A+B5oHD;EACE,oBAAA;EACA,qBAAA;EACA,oBAAA;EACA,mCAAA;EACA,sCAAA;E1B/NA,8FAAA;EACQ,sFAAA;E2B/DR,iBAAA;EACA,oBAAA;EhC86HD;AkBz9GD;EAAA;IA/DM,uBAAA;IACA,kBAAA;IACA,wBAAA;IlB4hHH;EkB/9GH;IAxDM,uBAAA;IACA,aAAA;IACA,wBAAA;IlB0hHH;EkBp+GH;IAjDM,uBAAA;IlBwhHH;EkBv+GH;IA7CM,uBAAA;IACA,wBAAA;IlBuhHH;EkB3+GH;;;IAvCQ,aAAA;IlBuhHL;EkBh/GH;IAjCM,aAAA;IlBohHH;EkBn/GH;IA7BM,kBAAA;IACA,wBAAA;IlBmhHH;EkBv/GH;;IApBM,uBAAA;IACA,eAAA;IACA,kBAAA;IACA,wBAAA;IlB+gHH;EkB9/GH;;IAdQ,iBAAA;IlBghHL;EkBlgHH;;IATM,oBAAA;IACA,gBAAA;IlB+gHH;EkBvgHH;IAHM,QAAA;IlB6gHH;EACF;A+BrrHC;EAAA;IANI,oBAAA;I/B+rHH;E+B7rHG;IACE,kBAAA;I/B+rHL;EACF;A+B9qHD;EAAA;IARI,aAAA;IACA,WAAA;IACA,gBAAA;IACA,iBAAA;IACA,gBAAA;IACA,mBAAA;I1B1PF,0BAAA;IACQ,kBAAA;ILq7HP;EACF;A+BprHD;EACE,eAAA;EHrUA,4BAAA;EACC,2BAAA;E5B4/HF;A+BprHD;EHzUE,8BAAA;EACC,6BAAA;EAOD,+BAAA;EACC,8BAAA;E5B0/HF;A+BhrHD;EChVE,iBAAA;EACA,oBAAA;EhCmgID;A+BjrHC;ECnVA,kBAAA;EACA,qBAAA;EhCugID;A+BlrHC;ECtVA,kBAAA;EACA,qBAAA;EhC2gID;A+B5qHD;EChWE,kBAAA;EACA,qBAAA;EhC+gID;A+BxqHD;EAAA;IAJI,aAAA;IACA,mBAAA;IACA,oBAAA;I/BgrHD;EACF;A+BvpHD;EAZE;IExWA,wBAAA;IjC+gIC;E+BtqHD;IE5WA,yBAAA;IF8WE,qBAAA;I/BwqHD;E+B1qHD;IAKI,iBAAA;I/BwqHH;EACF;A+B/pHD;EACE,2BAAA;EACA,uBAAA;E/BiqHD;A+BnqHD;EAKI,gBAAA;E/BiqHH;A+BhqHG;;EAEE,gBAAA;EACA,+BAAA;E/BkqHL;A+B3qHD;EAcI,gBAAA;E/BgqHH;A+B9qHD;EAmBM,gBAAA;E/B8pHL;A+B5pHK;;EAEE,gBAAA;EACA,+BAAA;E/B8pHP;A+B1pHK;;;EAGE,gBAAA;EACA,2BAAA;E/B4pHP;A+BxpHK;;;EAGE,gBAAA;EACA,+BAAA;E/B0pHP;A+BlsHD;EA8CI,uBAAA;E/BupHH;A+BtpHG;;EAEE,2BAAA;E/BwpHL;A+BzsHD;EAoDM,2BAAA;E/BwpHL;A+B5sHD;;EA0DI,uBAAA;E/BspHH;A+B/oHK;;;EAGE,2BAAA;EACA,gBAAA;E/BipHP;A+BhnHC;EAAA;IAzBQ,gBAAA;I/B6oHP;E+B5oHO;;IAEE,gBAAA;IACA,+BAAA;I/B8oHT;E+B1oHO;;;IAGE,gBAAA;IACA,2BAAA;I/B4oHT;E+BxoHO;;;IAGE,gBAAA;IACA,+BAAA;I/B0oHT;EACF;A+B5uHD;EA8GI,gBAAA;E/BioHH;A+BhoHG;EACE,gBAAA;E/BkoHL;A+BlvHD;EAqHI,gBAAA;E/BgoHH;A+B/nHG;;EAEE,gBAAA;E/BioHL;A+B7nHK;;;;EAEE,gBAAA;E/BioHP;A+BznHD;EACE,2BAAA;EACA,uBAAA;E/B2nHD;A+B7nHD;EAKI,gBAAA;E/B2nHH;A+B1nHG;;EAEE,gBAAA;EACA,+BAAA;E/B4nHL;A+BroHD;EAcI,gBAAA;E/B0nHH;A+BxoHD;EAmBM,gBAAA;E/BwnHL;A+BtnHK;;EAEE,gBAAA;EACA,+BAAA;E/BwnHP;A+BpnHK;;;EAGE,gBAAA;EACA,2BAAA;E/BsnHP;A+BlnHK;;;EAGE,gBAAA;EACA,+BAAA;E/BonHP;A+B5pHD;EA+CI,uBAAA;E/BgnHH;A+B/mHG;;EAEE,2BAAA;E/BinHL;A+BnqHD;EAqDM,2BAAA;E/BinHL;A+BtqHD;;EA2DI,uBAAA;E/B+mHH;A+BzmHK;;;EAGE,2BAAA;EACA,gBAAA;E/B2mHP;A+BpkHC;EAAA;IA/BQ,uBAAA;I/BumHP;E+BxkHD;IA5BQ,2BAAA;I/BumHP;E+B3kHD;IAzBQ,gBAAA;I/BumHP;E+BtmHO;;IAEE,gBAAA;IACA,+BAAA;I/BwmHT;E+BpmHO;;;IAGE,gBAAA;IACA,2BAAA;I/BsmHT;E+BlmHO;;;IAGE,gBAAA;IACA,+BAAA;I/BomHT;EACF;A+B5sHD;EA+GI,gBAAA;E/BgmHH;A+B/lHG;EACE,gBAAA;E/BimHL;A+BltHD;EAsHI,gBAAA;E/B+lHH;A+B9lHG;;EAEE,gBAAA;E/BgmHL;A+B5lHK;;;;EAEE,gBAAA;E/BgmHP;AkC1uID;EACE,mBAAA;EACA,qBAAA;EACA,kBAAA;EACA,2BAAA;EACA,oBAAA;ElC4uID;AkCjvID;EAQI,uBAAA;ElC4uIH;AkCpvID;EAWM,mBAAA;EACA,gBAAA;EACA,gBAAA;ElC4uIL;AkCzvID;EAkBI,gBAAA;ElC0uIH;AmC9vID;EACE,uBAAA;EACA,iBAAA;EACA,gBAAA;EACA,oBAAA;EnCgwID;AmCpwID;EAOI,iBAAA;EnCgwIH;AmCvwID;;EAUM,oBAAA;EACA,aAAA;EACA,mBAAA;EACA,yBAAA;EACA,uBAAA;EACA,gBAAA;EACA,2BAAA;EACA,2BAAA;EACA,mBAAA;EnCiwIL;AmC/vIG;;EAGI,gBAAA;EPXN,gCAAA;EACG,6BAAA;E5B4wIJ;AmC9vIG;;EPvBF,iCAAA;EACG,8BAAA;E5ByxIJ;AmCzvIG;;;;EAEE,gBAAA;EACA,2BAAA;EACA,uBAAA;EnC6vIL;AmCvvIG;;;;;;EAGE,YAAA;EACA,gBAAA;EACA,2BAAA;EACA,uBAAA;EACA,iBAAA;EnC4vIL;AmClzID;;;;;;EAiEM,gBAAA;EACA,2BAAA;EACA,uBAAA;EACA,qBAAA;EnCyvIL;AmChvID;;EC1EM,oBAAA;EACA,iBAAA;EpC8zIL;AoC5zIG;;ERMF,gCAAA;EACG,6BAAA;E5B0zIJ;AoC3zIG;;ERRF,iCAAA;EACG,8BAAA;E5Bu0IJ;AmC1vID;;EC/EM,mBAAA;EACA,iBAAA;EpC60IL;AoC30IG;;ERMF,gCAAA;EACG,6BAAA;E5By0IJ;AoC10IG;;ERRF,iCAAA;EACG,8BAAA;E5Bs1IJ;AqCz1ID;EACE,iBAAA;EACA,gBAAA;EACA,kBAAA;EACA,oBAAA;ErC21ID;AqC/1ID;EAOI,iBAAA;ErC21IH;AqCl2ID;;EAUM,uBAAA;EACA,mBAAA;EACA,2BAAA;EACA,2BAAA;EACA,qBAAA;ErC41IL;AqC12ID;;EAmBM,uBAAA;EACA,2BAAA;ErC21IL;AqC/2ID;;EA2BM,cAAA;ErCw1IL;AqCn3ID;;EAkCM,aAAA;ErCq1IL;AqCv3ID;;;;EA2CM,gBAAA;EACA,2BAAA;EACA,qBAAA;ErCk1IL;AsCh4ID;EACE,iBAAA;EACA,yBAAA;EACA,gBAAA;EACA,mBAAA;EACA,gBAAA;EACA,gBAAA;EACA,oBAAA;EACA,qBAAA;EACA,0BAAA;EACA,sBAAA;EtCk4ID;AsC93IG;;EAEE,gBAAA;EACA,uBAAA;EACA,iBAAA;EtCg4IL;AsC33IC;EACE,eAAA;EtC63IH;AsCz3IC;EACE,oBAAA;EACA,WAAA;EtC23IH;AsCp3ID;ECtCE,2BAAA;EvC65ID;AuC15IG;;EAEE,2BAAA;EvC45IL;AsCv3ID;EC1CE,2BAAA;EvCo6ID;AuCj6IG;;EAEE,2BAAA;EvCm6IL;AsC13ID;EC9CE,2BAAA;EvC26ID;AuCx6IG;;EAEE,2BAAA;EvC06IL;AsC73ID;EClDE,2BAAA;EvCk7ID;AuC/6IG;;EAEE,2BAAA;EvCi7IL;AsCh4ID;ECtDE,2BAAA;EvCy7ID;AuCt7IG;;EAEE,2BAAA;EvCw7IL;AsCn4ID;EC1DE,2BAAA;EvCg8ID;AuC77IG;;EAEE,2BAAA;EvC+7IL;AwCj8ID;EACE,uBAAA;EACA,iBAAA;EACA,kBAAA;EACA,iBAAA;EACA,mBAAA;EACA,gBAAA;EACA,gBAAA;EACA,0BAAA;EACA,qBAAA;EACA,oBAAA;EACA,2BAAA;EACA,qBAAA;ExCm8ID;AwCh8IC;EACE,eAAA;ExCk8IH;AwC97IC;EACE,oBAAA;EACA,WAAA;ExCg8IH;AwC97IC;EACE,QAAA;EACA,kBAAA;ExCg8IH;AwC37IG;;EAEE,gBAAA;EACA,uBAAA;EACA,iBAAA;ExC67IL;AwCx7IC;;EAEE,gBAAA;EACA,2BAAA;ExC07IH;AwCx7IC;EACE,cAAA;ExC07IH;AwCx7IC;EACE,mBAAA;ExC07IH;AwCx7IC;EACE,kBAAA;ExC07IH;AyC/+ID;EACE,oBAAA;EACA,qBAAA;EACA,gBAAA;EACA,2BAAA;EzCi/ID;AyCr/ID;;EAQI,gBAAA;EzCi/IH;AyCz/ID;EAWI,qBAAA;EACA,iBAAA;EACA,kBAAA;EzCi/IH;AyC9/ID;EAiBI,2BAAA;EzCg/IH;AyC7+IC;;EAEE,oBAAA;EzC++IH;AyCrgJD;EA0BI,iBAAA;EzC8+IH;AyC79ID;EAAA;IAbI,iBAAA;IzC8+ID;EyC5+IC;;IAEE,oBAAA;IACA,qBAAA;IzC8+IH;EyCt+IH;;IAHM,iBAAA;IzC6+IH;EACF;A0CrhJD;EACE,gBAAA;EACA,cAAA;EACA,qBAAA;EACA,yBAAA;EACA,2BAAA;EACA,2BAAA;EACA,oBAAA;ErCiLA,6CAAA;EACK,wCAAA;EACG,qCAAA;ELu2IT;A0CjiJD;;EAaI,mBAAA;EACA,oBAAA;E1CwhJH;A0CphJC;;;EAGE,uBAAA;E1CshJH;A0C3iJD;EA0BI,cAAA;EACA,gBAAA;E1CohJH;A2C7iJD;EACE,eAAA;EACA,qBAAA;EACA,+BAAA;EACA,oBAAA;E3C+iJD;A2CnjJD;EAQI,eAAA;EAEA,gBAAA;E3C6iJH;A2CvjJD;EAcI,mBAAA;E3C4iJH;A2C1jJD;;EAoBI,kBAAA;E3C0iJH;A2C9jJD;EAuBI,iBAAA;E3C0iJH;A2CliJD;;EAEE,qBAAA;E3CoiJD;A2CtiJD;;EAMI,oBAAA;EACA,WAAA;EACA,cAAA;EACA,gBAAA;E3CoiJH;A2C5hJD;ECrDE,2BAAA;EACA,uBAAA;EACA,gBAAA;E5ColJD;A2CjiJD;EChDI,2BAAA;E5ColJH;A2CpiJD;EC7CI,gBAAA;E5ColJH;A2CpiJD;ECxDE,2BAAA;EACA,uBAAA;EACA,gBAAA;E5C+lJD;A2CziJD;ECnDI,2BAAA;E5C+lJH;A2C5iJD;EChDI,gBAAA;E5C+lJH;A2C5iJD;EC3DE,2BAAA;EACA,uBAAA;EACA,gBAAA;E5C0mJD;A2CjjJD;ECtDI,2BAAA;E5C0mJH;A2CpjJD;ECnDI,gBAAA;E5C0mJH;A2CpjJD;EC9DE,2BAAA;EACA,uBAAA;EACA,gBAAA;E5CqnJD;A2CzjJD;ECzDI,2BAAA;E5CqnJH;A2C5jJD;ECtDI,gBAAA;E5CqnJH;A6CvnJD;EACE;IAAQ,6BAAA;I7C0nJP;E6CznJD;IAAQ,0BAAA;I7C4nJP;EACF;A6CznJD;EACE;IAAQ,6BAAA;I7C4nJP;E6C3nJD;IAAQ,0BAAA;I7C8nJP;EACF;A6CjoJD;EACE;IAAQ,6BAAA;I7C4nJP;E6C3nJD;IAAQ,0BAAA;I7C8nJP;EACF;A6CvnJD;EACE,kBAAA;EACA,cAAA;EACA,qBAAA;EACA,2BAAA;EACA,oBAAA;ExCsCA,wDAAA;EACQ,gDAAA;ELolJT;A6CtnJD;EACE,aAAA;EACA,WAAA;EACA,cAAA;EACA,iBAAA;EACA,mBAAA;EACA,gBAAA;EACA,oBAAA;EACA,2BAAA;ExCyBA,wDAAA;EACQ,gDAAA;EAyHR,qCAAA;EACK,gCAAA;EACG,6BAAA;ELw+IT;A6CnnJD;;ECCI,+MAAA;EACA,0MAAA;EACA,uMAAA;EDAF,oCAAA;UAAA,4BAAA;E7CunJD;A6ChnJD;;ExC5CE,4DAAA;EACK,uDAAA;EACG,oDAAA;ELgqJT;A6C7mJD;EErEE,2BAAA;E/CqrJD;A+ClrJC;EDgDE,+MAAA;EACA,0MAAA;EACA,uMAAA;E9CqoJH;A6CjnJD;EEzEE,2BAAA;E/C6rJD;A+C1rJC;EDgDE,+MAAA;EACA,0MAAA;EACA,uMAAA;E9C6oJH;A6CrnJD;EE7EE,2BAAA;E/CqsJD;A+ClsJC;EDgDE,+MAAA;EACA,0MAAA;EACA,uMAAA;E9CqpJH;A6CznJD;EEjFE,2BAAA;E/C6sJD;A+C1sJC;EDgDE,+MAAA;EACA,0MAAA;EACA,uMAAA;E9C6pJH;AgDrtJD;EAEE,kBAAA;EhDstJD;AgDptJC;EACE,eAAA;EhDstJH;AgDltJD;;EAEE,oBAAA;EhDotJD;AgDjtJD;;EAEE,qBAAA;EhDmtJD;AgDhtJD;;;EAGE,qBAAA;EACA,qBAAA;EhDktJD;AgD/sJD;EACE,wBAAA;EhDitJD;AgD9sJD;EACE,wBAAA;EhDgtJD;AgD5sJD;EACE,eAAA;EACA,oBAAA;EhD8sJD;AgDxsJD;EACE,iBAAA;EACA,kBAAA;EhD0sJD;AiD9uJD;EAEE,qBAAA;EACA,iBAAA;EjD+uJD;AiDvuJD;EACE,oBAAA;EACA,gBAAA;EACA,oBAAA;EAEA,qBAAA;EACA,2BAAA;EACA,2BAAA;EjDwuJD;AiDruJC;ErB3BA,8BAAA;EACC,6BAAA;E5BmwJF;AiDtuJC;EACE,kBAAA;ErBvBF,iCAAA;EACC,gCAAA;E5BgwJF;AiD/tJD;EACE,gBAAA;EjDiuJD;AiDluJD;EAII,gBAAA;EjDiuJH;AiD7tJC;;EAEE,uBAAA;EACA,gBAAA;EACA,2BAAA;EjD+tJH;AiDztJC;;;EAGE,2BAAA;EACA,gBAAA;EACA,qBAAA;EjD2tJH;AiDhuJC;;;EASI,gBAAA;EjD4tJL;AiDruJC;;;EAYI,gBAAA;EjD8tJL;AiDztJC;;;EAGE,YAAA;EACA,gBAAA;EACA,2BAAA;EACA,uBAAA;EjD2tJH;AiDjuJC;;;;;;;;;EAYI,gBAAA;EjDguJL;AiD5uJC;;;EAeI,gBAAA;EjDkuJL;AkD9zJC;EACE,gBAAA;EACA,2BAAA;ElDg0JH;AkD9zJG;EACE,gBAAA;ElDg0JL;AkDj0JG;EAII,gBAAA;ElDg0JP;AkD7zJK;;EAEE,gBAAA;EACA,2BAAA;ElD+zJP;AkD7zJK;;;EAGE,aAAA;EACA,2BAAA;EACA,uBAAA;ElD+zJP;AkDp1JC;EACE,gBAAA;EACA,2BAAA;ElDs1JH;AkDp1JG;EACE,gBAAA;ElDs1JL;AkDv1JG;EAII,gBAAA;ElDs1JP;AkDn1JK;;EAEE,gBAAA;EACA,2BAAA;ElDq1JP;AkDn1JK;;;EAGE,aAAA;EACA,2BAAA;EACA,uBAAA;ElDq1JP;AkD12JC;EACE,gBAAA;EACA,2BAAA;ElD42JH;AkD12JG;EACE,gBAAA;ElD42JL;AkD72JG;EAII,gBAAA;ElD42JP;AkDz2JK;;EAEE,gBAAA;EACA,2BAAA;ElD22JP;AkDz2JK;;;EAGE,aAAA;EACA,2BAAA;EACA,uBAAA;ElD22JP;AkDh4JC;EACE,gBAAA;EACA,2BAAA;ElDk4JH;AkDh4JG;EACE,gBAAA;ElDk4JL;AkDn4JG;EAII,gBAAA;ElDk4JP;AkD/3JK;;EAEE,gBAAA;EACA,2BAAA;ElDi4JP;AkD/3JK;;;EAGE,aAAA;EACA,2BAAA;EACA,uBAAA;ElDi4JP;AiDryJD;EACE,eAAA;EACA,oBAAA;EjDuyJD;AiDryJD;EACE,kBAAA;EACA,kBAAA;EjDuyJD;AmD35JD;EACE,qBAAA;EACA,2BAAA;EACA,+BAAA;EACA,oBAAA;E9C0DA,mDAAA;EACQ,2CAAA;ELo2JT;AmD15JD;EACE,eAAA;EnD45JD;AmDv5JD;EACE,oBAAA;EACA,sCAAA;EvBpBA,8BAAA;EACC,6BAAA;E5B86JF;AmD75JD;EAMI,gBAAA;EnD05JH;AmDr5JD;EACE,eAAA;EACA,kBAAA;EACA,iBAAA;EACA,gBAAA;EnDu5JD;AmD35JD;EAOI,gBAAA;EnDu5JH;AmDl5JD;EACE,oBAAA;EACA,2BAAA;EACA,+BAAA;EvBpCA,iCAAA;EACC,gCAAA;E5By7JF;AmD54JD;;EAGI,kBAAA;EnD64JH;AmDh5JD;;EAMM,qBAAA;EACA,kBAAA;EnD84JL;AmD14JG;;EAEI,eAAA;EvBnEN,8BAAA;EACC,6BAAA;E5Bg9JF;AmDz4JG;;EAEI,kBAAA;EvBlEN,iCAAA;EACC,gCAAA;E5B88JF;AmDt4JD;EAEI,qBAAA;EnDu4JH;AmDp4JD;EACE,qBAAA;EnDs4JD;AmD93JD;;;EAII,kBAAA;EnD+3JH;AmDn4JD;;;EAOM,oBAAA;EACA,qBAAA;EnDi4JL;AmDz4JD;;EvB/FE,8BAAA;EACC,6BAAA;E5B4+JF;AmD94JD;;;;EAmBQ,6BAAA;EACA,8BAAA;EnDi4JP;AmDr5JD;;;;;;;;EAwBU,6BAAA;EnDu4JT;AmD/5JD;;;;;;;;EA4BU,8BAAA;EnD64JT;AmDz6JD;;EvBvFE,iCAAA;EACC,gCAAA;E5BogKF;AmD96JD;;;;EAyCQ,gCAAA;EACA,iCAAA;EnD24JP;AmDr7JD;;;;;;;;EA8CU,gCAAA;EnDi5JT;AmD/7JD;;;;;;;;EAkDU,iCAAA;EnDu5JT;AmDz8JD;;;;EA2DI,+BAAA;EnDo5JH;AmD/8JD;;EA+DI,eAAA;EnDo5JH;AmDn9JD;;EAmEI,WAAA;EnDo5JH;AmDv9JD;;;;;;;;;;;;EA0EU,gBAAA;EnD25JT;AmDr+JD;;;;;;;;;;;;EA8EU,iBAAA;EnDq6JT;AmDn/JD;;;;;;;;EAuFU,kBAAA;EnDs6JT;AmD7/JD;;;;;;;;EAgGU,kBAAA;EnDu6JT;AmDvgKD;EAsGI,WAAA;EACA,kBAAA;EnDo6JH;AmD15JD;EACE,qBAAA;EnD45JD;AmD75JD;EAKI,kBAAA;EACA,oBAAA;EnD25JH;AmDj6JD;EASM,iBAAA;EnD25JL;AmDp6JD;EAcI,kBAAA;EnDy5JH;AmDv6JD;;EAkBM,+BAAA;EnDy5JL;AmD36JD;EAuBI,eAAA;EnDu5JH;AmD96JD;EAyBM,kCAAA;EnDw5JL;AmDj5JD;EChPE,uBAAA;EpDooKD;AoDloKC;EACE,gBAAA;EACA,2BAAA;EACA,uBAAA;EpDooKH;AoDvoKC;EAMI,2BAAA;EpDooKL;AoD1oKC;EASI,gBAAA;EACA,2BAAA;EpDooKL;AoDjoKC;EAEI,8BAAA;EpDkoKL;AmDh6JD;ECnPE,uBAAA;EpDspKD;AoDppKC;EACE,gBAAA;EACA,2BAAA;EACA,uBAAA;EpDspKH;AoDzpKC;EAMI,2BAAA;EpDspKL;AoD5pKC;EASI,gBAAA;EACA,2BAAA;EpDspKL;AoDnpKC;EAEI,8BAAA;EpDopKL;AmD/6JD;ECtPE,uBAAA;EpDwqKD;AoDtqKC;EACE,gBAAA;EACA,2BAAA;EACA,uBAAA;EpDwqKH;AoD3qKC;EAMI,2BAAA;EpDwqKL;AoD9qKC;EASI,gBAAA;EACA,2BAAA;EpDwqKL;AoDrqKC;EAEI,8BAAA;EpDsqKL;AmD97JD;ECzPE,uBAAA;EpD0rKD;AoDxrKC;EACE,gBAAA;EACA,2BAAA;EACA,uBAAA;EpD0rKH;AoD7rKC;EAMI,2BAAA;EpD0rKL;AoDhsKC;EASI,gBAAA;EACA,2BAAA;EpD0rKL;AoDvrKC;EAEI,8BAAA;EpDwrKL;AmD78JD;EC5PE,uBAAA;EpD4sKD;AoD1sKC;EACE,gBAAA;EACA,2BAAA;EACA,uBAAA;EpD4sKH;AoD/sKC;EAMI,2BAAA;EpD4sKL;AoDltKC;EASI,gBAAA;EACA,2BAAA;EpD4sKL;AoDzsKC;EAEI,8BAAA;EpD0sKL;AmD59JD;EC/PE,uBAAA;EpD8tKD;AoD5tKC;EACE,gBAAA;EACA,2BAAA;EACA,uBAAA;EpD8tKH;AoDjuKC;EAMI,2BAAA;EpD8tKL;AoDpuKC;EASI,gBAAA;EACA,2BAAA;EpD8tKL;AoD3tKC;EAEI,8BAAA;EpD4tKL;AqD5uKD;EACE,oBAAA;EACA,gBAAA;EACA,WAAA;EACA,YAAA;EACA,kBAAA;ErD8uKD;AqDnvKD;;;;;EAYI,oBAAA;EACA,QAAA;EACA,SAAA;EACA,WAAA;EACA,cAAA;EACA,aAAA;EACA,WAAA;ErD8uKH;AqD1uKC;EACE,wBAAA;ErD4uKH;AqDxuKC;EACE,qBAAA;ErD0uKH;AsDpwKD;EACE,kBAAA;EACA,eAAA;EACA,qBAAA;EACA,2BAAA;EACA,2BAAA;EACA,oBAAA;EjDwDA,yDAAA;EACQ,iDAAA;EL+sKT;AsD9wKD;EASI,oBAAA;EACA,mCAAA;EtDwwKH;AsDnwKD;EACE,eAAA;EACA,oBAAA;EtDqwKD;AsDnwKD;EACE,cAAA;EACA,oBAAA;EtDqwKD;AuD3xKD;EACE,cAAA;EACA,iBAAA;EACA,mBAAA;EACA,gBAAA;EACA,gBAAA;EACA,8BAAA;EjCRA,cAAA;EAGA,2BAAA;EtBoyKD;AuD5xKC;;EAEE,gBAAA;EACA,uBAAA;EACA,iBAAA;EjCfF,cAAA;EAGA,2BAAA;EtB4yKD;AuDzxKC;EACE,YAAA;EACA,iBAAA;EACA,yBAAA;EACA,WAAA;EACA,0BAAA;EvD2xKH;AwD/yKD;EACE,kBAAA;ExDizKD;AwD7yKD;EACE,eAAA;EACA,kBAAA;EACA,iBAAA;EACA,QAAA;EACA,UAAA;EACA,WAAA;EACA,SAAA;EACA,eAAA;EACA,mCAAA;EAIA,YAAA;ExD4yKD;AwDzyKC;EnD+GA,uCAAA;EACI,mCAAA;EACC,kCAAA;EACG,+BAAA;EAkER,qDAAA;EAEK,2CAAA;EACG,qCAAA;EL4nKT;AwD/yKC;EnD2GA,oCAAA;EACI,gCAAA;EACC,+BAAA;EACG,4BAAA;ELusKT;AwDnzKD;EACE,oBAAA;EACA,kBAAA;ExDqzKD;AwDjzKD;EACE,oBAAA;EACA,aAAA;EACA,cAAA;ExDmzKD;AwD/yKD;EACE,oBAAA;EACA,2BAAA;EACA,2BAAA;EACA,sCAAA;EACA,oBAAA;EnDaA,kDAAA;EACQ,0CAAA;EmDZR,sCAAA;UAAA,8BAAA;EAEA,YAAA;ExDizKD;AwD7yKD;EACE,oBAAA;EACA,QAAA;EACA,UAAA;EACA,SAAA;EACA,2BAAA;ExD+yKD;AwD7yKC;ElCnEA,YAAA;EAGA,0BAAA;EtBi3KD;AwDhzKC;ElCpEA,cAAA;EAGA,2BAAA;EtBq3KD;AwD/yKD;EACE,eAAA;EACA,kCAAA;EACA,2BAAA;ExDizKD;AwD9yKD;EACE,kBAAA;ExDgzKD;AwD5yKD;EACE,WAAA;EACA,yBAAA;ExD8yKD;AwDzyKD;EACE,oBAAA;EACA,eAAA;ExD2yKD;AwDvyKD;EACE,eAAA;EACA,mBAAA;EACA,+BAAA;ExDyyKD;AwD5yKD;EAQI,kBAAA;EACA,kBAAA;ExDuyKH;AwDhzKD;EAaI,mBAAA;ExDsyKH;AwDnzKD;EAiBI,gBAAA;ExDqyKH;AwDhyKD;EACE,oBAAA;EACA,cAAA;EACA,aAAA;EACA,cAAA;EACA,kBAAA;ExDkyKD;AwDhxKD;EAZE;IACE,cAAA;IACA,mBAAA;IxD+xKD;EwD7xKD;InDrEA,mDAAA;IACQ,2CAAA;ILq2KP;EwD5xKD;IAAY,cAAA;IxD+xKX;EACF;AwD1xKD;EAFE;IAAY,cAAA;IxDgyKX;EACF;AyD76KD;EACE,oBAAA;EACA,eAAA;EACA,gBAAA;EACA,qBAAA;EAEA,6DAAA;EACA,iBAAA;EACA,qBAAA;EACA,kBAAA;EnCZA,YAAA;EAGA,0BAAA;EtBy7KD;AyD76KC;EnCfA,cAAA;EAGA,2BAAA;EtB67KD;AyDh7KC;EAAW,kBAAA;EAAmB,gBAAA;EzDo7K/B;AyDn7KC;EAAW,kBAAA;EAAmB,gBAAA;EzDu7K/B;AyDt7KC;EAAW,iBAAA;EAAmB,gBAAA;EzD07K/B;AyDz7KC;EAAW,mBAAA;EAAmB,gBAAA;EzD67K/B;AyDz7KD;EACE,kBAAA;EACA,kBAAA;EACA,gBAAA;EACA,oBAAA;EACA,uBAAA;EACA,2BAAA;EACA,oBAAA;EzD27KD;AyDv7KD;EACE,oBAAA;EACA,UAAA;EACA,WAAA;EACA,2BAAA;EACA,qBAAA;EzDy7KD;AyDr7KC;EACE,WAAA;EACA,WAAA;EACA,mBAAA;EACA,yBAAA;EACA,2BAAA;EzDu7KH;AyDr7KC;EACE,WAAA;EACA,YAAA;EACA,qBAAA;EACA,yBAAA;EACA,2BAAA;EzDu7KH;AyDr7KC;EACE,WAAA;EACA,WAAA;EACA,qBAAA;EACA,yBAAA;EACA,2BAAA;EzDu7KH;AyDr7KC;EACE,UAAA;EACA,SAAA;EACA,kBAAA;EACA,6BAAA;EACA,6BAAA;EzDu7KH;AyDr7KC;EACE,UAAA;EACA,UAAA;EACA,kBAAA;EACA,6BAAA;EACA,4BAAA;EzDu7KH;AyDr7KC;EACE,QAAA;EACA,WAAA;EACA,mBAAA;EACA,yBAAA;EACA,8BAAA;EzDu7KH;AyDr7KC;EACE,QAAA;EACA,YAAA;EACA,kBAAA;EACA,yBAAA;EACA,8BAAA;EzDu7KH;AyDr7KC;EACE,QAAA;EACA,WAAA;EACA,kBAAA;EACA,yBAAA;EACA,8BAAA;EzDu7KH;A0DthLD;EACE,oBAAA;EACA,QAAA;EACA,SAAA;EACA,eAAA;EACA,eAAA;EACA,kBAAA;EACA,cAAA;EAEA,6DAAA;EACA,iBAAA;EACA,qBAAA;EACA,yBAAA;EACA,kBAAA;EACA,2BAAA;EACA,sCAAA;UAAA,8BAAA;EACA,2BAAA;EACA,sCAAA;EACA,oBAAA;ErD6CA,mDAAA;EACQ,2CAAA;EqD1CR,qBAAA;E1DshLD;A0DnhLC;EAAY,mBAAA;E1DshLb;A0DrhLC;EAAY,mBAAA;E1DwhLb;A0DvhLC;EAAY,kBAAA;E1D0hLb;A0DzhLC;EAAY,oBAAA;E1D4hLb;A0DzhLD;EACE,WAAA;EACA,mBAAA;EACA,iBAAA;EACA,2BAAA;EACA,kCAAA;EACA,4BAAA;E1D2hLD;A0DxhLD;EACE,mBAAA;E1D0hLD;A0DlhLC;;EAEE,oBAAA;EACA,gBAAA;EACA,UAAA;EACA,WAAA;EACA,2BAAA;EACA,qBAAA;E1DohLH;A0DjhLD;EACE,oBAAA;E1DmhLD;A0DjhLD;EACE,oBAAA;EACA,aAAA;E1DmhLD;A0D/gLC;EACE,WAAA;EACA,oBAAA;EACA,wBAAA;EACA,2BAAA;EACA,uCAAA;EACA,eAAA;E1DihLH;A0DhhLG;EACE,cAAA;EACA,aAAA;EACA,oBAAA;EACA,wBAAA;EACA,2BAAA;E1DkhLL;A0D/gLC;EACE,UAAA;EACA,aAAA;EACA,mBAAA;EACA,sBAAA;EACA,6BAAA;EACA,yCAAA;E1DihLH;A0DhhLG;EACE,cAAA;EACA,WAAA;EACA,eAAA;EACA,sBAAA;EACA,6BAAA;E1DkhLL;A0D/gLC;EACE,WAAA;EACA,oBAAA;EACA,qBAAA;EACA,8BAAA;EACA,0CAAA;EACA,YAAA;E1DihLH;A0DhhLG;EACE,cAAA;EACA,UAAA;EACA,oBAAA;EACA,qBAAA;EACA,8BAAA;E1DkhLL;A0D9gLC;EACE,UAAA;EACA,cAAA;EACA,mBAAA;EACA,uBAAA;EACA,4BAAA;EACA,wCAAA;E1DghLH;A0D/gLG;EACE,cAAA;EACA,YAAA;EACA,uBAAA;EACA,4BAAA;EACA,eAAA;E1DihLL;A2D9oLD;EACE,oBAAA;E3DgpLD;A2D7oLD;EACE,oBAAA;EACA,kBAAA;EACA,aAAA;E3D+oLD;A2DlpLD;EAMI,eAAA;EACA,oBAAA;EtD6KF,2CAAA;EACK,sCAAA;EACG,mCAAA;ELm+KT;A2DzpLD;;EAcM,gBAAA;E3D+oLL;A2DrnLC;EAAA;IArBI,wDAAA;SAAA,8CAAA;YAAA,wCAAA;IACA,qCAAA;YAAA,6BAAA;IACA,2BAAA;YAAA,mBAAA;I3D8oLH;E2D5oLG;;IAEE,4CAAA;YAAA,oCAAA;IACA,SAAA;I3D8oLL;E2D5oLG;;IAEE,6CAAA;YAAA,qCAAA;IACA,SAAA;I3D8oLL;E2D5oLG;;;IAGE,yCAAA;YAAA,iCAAA;IACA,SAAA;I3D8oLL;EACF;A2DprLD;;;EA6CI,gBAAA;E3D4oLH;A2DzrLD;EAiDI,SAAA;E3D2oLH;A2D5rLD;;EAsDI,oBAAA;EACA,QAAA;EACA,aAAA;E3D0oLH;A2DlsLD;EA4DI,YAAA;E3DyoLH;A2DrsLD;EA+DI,aAAA;E3DyoLH;A2DxsLD;;EAmEI,SAAA;E3DyoLH;A2D5sLD;EAuEI,aAAA;E3DwoLH;A2D/sLD;EA0EI,YAAA;E3DwoLH;A2DhoLD;EACE,oBAAA;EACA,QAAA;EACA,SAAA;EACA,WAAA;EACA,YAAA;ErC9FA,cAAA;EAGA,2BAAA;EqC6FA,iBAAA;EACA,gBAAA;EACA,oBAAA;EACA,2CAAA;E3DmoLD;A2D9nLC;EblGE,oGAAA;EACA,+FAAA;EACA,sHAAA;EAAA,gGAAA;EACA,6BAAA;EACA,wHAAA;E9CmuLH;A2DloLC;EACE,YAAA;EACA,UAAA;EbvGA,oGAAA;EACA,+FAAA;EACA,sHAAA;EAAA,gGAAA;EACA,6BAAA;EACA,wHAAA;E9C4uLH;A2DpoLC;;EAEE,YAAA;EACA,gBAAA;EACA,uBAAA;ErCtHF,cAAA;EAGA,2BAAA;EtB2vLD;A2DrqLD;;;;EAsCI,oBAAA;EACA,UAAA;EACA,YAAA;EACA,uBAAA;E3DqoLH;A2D9qLD;;EA6CI,WAAA;EACA,oBAAA;E3DqoLH;A2DnrLD;;EAkDI,YAAA;EACA,qBAAA;E3DqoLH;A2DxrLD;;EAuDI,aAAA;EACA,cAAA;EACA,mBAAA;EACA,oBAAA;E3DqoLH;A2DhoLG;EACE,kBAAA;E3DkoLL;A2D9nLG;EACE,kBAAA;E3DgoLL;A2DtnLD;EACE,oBAAA;EACA,cAAA;EACA,WAAA;EACA,aAAA;EACA,YAAA;EACA,mBAAA;EACA,iBAAA;EACA,kBAAA;EACA,oBAAA;E3DwnLD;A2DjoLD;EAYI,uBAAA;EACA,aAAA;EACA,cAAA;EACA,aAAA;EACA,qBAAA;EACA,2BAAA;EACA,qBAAA;EACA,iBAAA;EAUA,2BAAA;EACA,oCAAA;E3D+mLH;A2D7oLD;EAiCI,WAAA;EACA,aAAA;EACA,cAAA;EACA,2BAAA;E3D+mLH;A2DxmLD;EACE,oBAAA;EACA,WAAA;EACA,YAAA;EACA,cAAA;EACA,aAAA;EACA,mBAAA;EACA,sBAAA;EACA,gBAAA;EACA,oBAAA;EACA,2CAAA;E3D0mLD;A2DzmLC;EACE,mBAAA;E3D2mLH;A2DlkLD;EAhCE;;;;IAKI,aAAA;IACA,cAAA;IACA,mBAAA;IACA,iBAAA;I3DomLH;E2D5mLD;;IAYI,oBAAA;I3DomLH;E2DhnLD;;IAgBI,qBAAA;I3DomLH;E2D/lLD;IACE,WAAA;IACA,YAAA;IACA,sBAAA;I3DimLD;E2D7lLD;IACE,cAAA;I3D+lLD;EACF;A4D31LC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEE,cAAA;EACA,gBAAA;E5Dy3LH;A4Dv3LC;;;;;;;;;;;;;;;EACE,aAAA;E5Du4LH;AiC/4LD;E4BRE,gBAAA;EACA,mBAAA;EACA,oBAAA;E7D05LD;AiCj5LD;EACE,yBAAA;EjCm5LD;AiCj5LD;EACE,wBAAA;EjCm5LD;AiC34LD;EACE,0BAAA;EjC64LD;AiC34LD;EACE,2BAAA;EjC64LD;AiC34LD;EACE,oBAAA;EjC64LD;AiC34LD;E6BzBE,aAAA;EACA,oBAAA;EACA,mBAAA;EACA,+BAAA;EACA,WAAA;E9Du6LD;AiCz4LD;EACE,0BAAA;EACA,+BAAA;EjC24LD;AiCp4LD;EACE,iBAAA;EjCs4LD;A+Dx6LD;EACE,qBAAA;E/D06LD;A+Dp6LD;;;;ECdE,0BAAA;EhEw7LD;A+Dn6LD;;;;;;;;;;;;EAYE,0BAAA;E/Dq6LD;A+D95LD;EAAA;IChDE,2BAAA;IhEk9LC;EgEj9LD;IAAU,gBAAA;IhEo9LT;EgEn9LD;IAAU,+BAAA;IhEs9LT;EgEr9LD;;IACU,gCAAA;IhEw9LT;EACF;A+Dx6LD;EAAA;IAFI,2BAAA;I/D86LD;EACF;A+Dx6LD;EAAA;IAFI,4BAAA;I/D86LD;EACF;A+Dx6LD;EAAA;IAFI,kCAAA;I/D86LD;EACF;A+Dv6LD;EAAA;ICrEE,2BAAA;IhEg/LC;EgE/+LD;IAAU,gBAAA;IhEk/LT;EgEj/LD;IAAU,+BAAA;IhEo/LT;EgEn/LD;;IACU,gCAAA;IhEs/LT;EACF;A+Dj7LD;EAAA;IAFI,2BAAA;I/Du7LD;EACF;A+Dj7LD;EAAA;IAFI,4BAAA;I/Du7LD;EACF;A+Dj7LD;EAAA;IAFI,kCAAA;I/Du7LD;EACF;A+Dh7LD;EAAA;IC1FE,2BAAA;IhE8gMC;EgE7gMD;IAAU,gBAAA;IhEghMT;EgE/gMD;IAAU,+BAAA;IhEkhMT;EgEjhMD;;IACU,gCAAA;IhEohMT;EACF;A+D17LD;EAAA;IAFI,2BAAA;I/Dg8LD;EACF;A+D17LD;EAAA;IAFI,4BAAA;I/Dg8LD;EACF;A+D17LD;EAAA;IAFI,kCAAA;I/Dg8LD;EACF;A+Dz7LD;EAAA;IC/GE,2BAAA;IhE4iMC;EgE3iMD;IAAU,gBAAA;IhE8iMT;EgE7iMD;IAAU,+BAAA;IhEgjMT;EgE/iMD;;IACU,gCAAA;IhEkjMT;EACF;A+Dn8LD;EAAA;IAFI,2BAAA;I/Dy8LD;EACF;A+Dn8LD;EAAA;IAFI,4BAAA;I/Dy8LD;EACF;A+Dn8LD;EAAA;IAFI,kCAAA;I/Dy8LD;EACF;A+Dl8LD;EAAA;IC5HE,0BAAA;IhEkkMC;EACF;A+Dl8LD;EAAA;ICjIE,0BAAA;IhEukMC;EACF;A+Dl8LD;EAAA;ICtIE,0BAAA;IhE4kMC;EACF;A+Dl8LD;EAAA;IC3IE,0BAAA;IhEilMC;EACF;A+D/7LD;ECnJE,0BAAA;EhEqlMD;A+D57LD;EAAA;ICjKE,2BAAA;IhEimMC;EgEhmMD;IAAU,gBAAA;IhEmmMT;EgElmMD;IAAU,+BAAA;IhEqmMT;EgEpmMD;;IACU,gCAAA;IhEumMT;EACF;A+D18LD;EACE,0BAAA;E/D48LD;A+Dv8LD;EAAA;IAFI,2BAAA;I/D68LD;EACF;A+D38LD;EACE,0BAAA;E/D68LD;A+Dx8LD;EAAA;IAFI,4BAAA;I/D88LD;EACF;A+D58LD;EACE,0BAAA;E/D88LD;A+Dz8LD;EAAA;IAFI,kCAAA;I/D+8LD;EACF;A+Dx8LD;EAAA;ICpLE,0BAAA;IhEgoMC;EACF","file":"bootstrap.css","sourcesContent":["/*! normalize.css v3.0.2 | MIT License | git.io/normalize */\nhtml {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n}\nbody {\n margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n vertical-align: baseline;\n}\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n[hidden],\ntemplate {\n display: none;\n}\na {\n background-color: transparent;\n}\na:active,\na:hover {\n outline: 0;\n}\nabbr[title] {\n border-bottom: 1px dotted;\n}\nb,\nstrong {\n font-weight: bold;\n}\ndfn {\n font-style: italic;\n}\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\nmark {\n background: #ff0;\n color: #000;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\nsup {\n top: -0.5em;\n}\nsub {\n bottom: -0.25em;\n}\nimg {\n border: 0;\n}\nsvg:not(:root) {\n overflow: hidden;\n}\nfigure {\n margin: 1em 40px;\n}\nhr {\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n height: 0;\n}\npre {\n overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit;\n font: inherit;\n margin: 0;\n}\nbutton {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\ninput {\n line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box;\n padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: textfield;\n -moz-box-sizing: content-box;\n -webkit-box-sizing: content-box;\n box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n border: 0;\n padding: 0;\n}\ntextarea {\n overflow: auto;\n}\noptgroup {\n font-weight: bold;\n}\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\ntd,\nth {\n padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important;\n box-shadow: none !important;\n text-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n img {\n max-width: 100% !important;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n select {\n background: #fff !important;\n }\n .navbar {\n display: none;\n }\n .btn > .caret,\n .dropup > .btn > .caret {\n border-top-color: #000 !important;\n }\n .label {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('../fonts/glyphicons-halflings-regular.eot');\n src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');\n}\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n content: \"\\2a\";\n}\n.glyphicon-plus:before {\n content: \"\\2b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n content: \"\\270f\";\n}\n.glyphicon-glass:before {\n content: \"\\e001\";\n}\n.glyphicon-music:before {\n content: \"\\e002\";\n}\n.glyphicon-search:before {\n content: \"\\e003\";\n}\n.glyphicon-heart:before {\n content: \"\\e005\";\n}\n.glyphicon-star:before {\n content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n content: \"\\e007\";\n}\n.glyphicon-user:before {\n content: \"\\e008\";\n}\n.glyphicon-film:before {\n content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n content: \"\\e010\";\n}\n.glyphicon-th:before {\n content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n content: \"\\e012\";\n}\n.glyphicon-ok:before {\n content: \"\\e013\";\n}\n.glyphicon-remove:before {\n content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n content: \"\\e016\";\n}\n.glyphicon-off:before {\n content: \"\\e017\";\n}\n.glyphicon-signal:before {\n content: \"\\e018\";\n}\n.glyphicon-cog:before {\n content: \"\\e019\";\n}\n.glyphicon-trash:before {\n content: \"\\e020\";\n}\n.glyphicon-home:before {\n content: \"\\e021\";\n}\n.glyphicon-file:before {\n content: \"\\e022\";\n}\n.glyphicon-time:before {\n content: \"\\e023\";\n}\n.glyphicon-road:before {\n content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n content: \"\\e025\";\n}\n.glyphicon-download:before {\n content: \"\\e026\";\n}\n.glyphicon-upload:before {\n content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n content: \"\\e032\";\n}\n.glyphicon-lock:before {\n content: \"\\e033\";\n}\n.glyphicon-flag:before {\n content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n content: \"\\e040\";\n}\n.glyphicon-tag:before {\n content: \"\\e041\";\n}\n.glyphicon-tags:before {\n content: \"\\e042\";\n}\n.glyphicon-book:before {\n content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n content: \"\\e044\";\n}\n.glyphicon-print:before {\n content: \"\\e045\";\n}\n.glyphicon-camera:before {\n content: \"\\e046\";\n}\n.glyphicon-font:before {\n content: \"\\e047\";\n}\n.glyphicon-bold:before {\n content: \"\\e048\";\n}\n.glyphicon-italic:before {\n content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n content: \"\\e055\";\n}\n.glyphicon-list:before {\n content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n content: \"\\e059\";\n}\n.glyphicon-picture:before {\n content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n content: \"\\e063\";\n}\n.glyphicon-tint:before {\n content: \"\\e064\";\n}\n.glyphicon-edit:before {\n content: \"\\e065\";\n}\n.glyphicon-share:before {\n content: \"\\e066\";\n}\n.glyphicon-check:before {\n content: \"\\e067\";\n}\n.glyphicon-move:before {\n content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n content: \"\\e070\";\n}\n.glyphicon-backward:before {\n content: \"\\e071\";\n}\n.glyphicon-play:before {\n content: \"\\e072\";\n}\n.glyphicon-pause:before {\n content: \"\\e073\";\n}\n.glyphicon-stop:before {\n content: \"\\e074\";\n}\n.glyphicon-forward:before {\n content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n content: \"\\e077\";\n}\n.glyphicon-eject:before {\n content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n content: \"\\e101\";\n}\n.glyphicon-gift:before {\n content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n content: \"\\e103\";\n}\n.glyphicon-fire:before {\n content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n content: \"\\e107\";\n}\n.glyphicon-plane:before {\n content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n content: \"\\e109\";\n}\n.glyphicon-random:before {\n content: \"\\e110\";\n}\n.glyphicon-comment:before {\n content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n content: \"\\e122\";\n}\n.glyphicon-bell:before {\n content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n content: \"\\e134\";\n}\n.glyphicon-globe:before {\n content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n content: \"\\e137\";\n}\n.glyphicon-filter:before {\n content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n content: \"\\e143\";\n}\n.glyphicon-link:before {\n content: \"\\e144\";\n}\n.glyphicon-phone:before {\n content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n content: \"\\e146\";\n}\n.glyphicon-usd:before {\n content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n content: \"\\e149\";\n}\n.glyphicon-sort:before {\n content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n content: \"\\e157\";\n}\n.glyphicon-expand:before {\n content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n content: \"\\e161\";\n}\n.glyphicon-flash:before {\n content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n content: \"\\e164\";\n}\n.glyphicon-record:before {\n content: \"\\e165\";\n}\n.glyphicon-save:before {\n content: \"\\e166\";\n}\n.glyphicon-open:before {\n content: \"\\e167\";\n}\n.glyphicon-saved:before {\n content: \"\\e168\";\n}\n.glyphicon-import:before {\n content: \"\\e169\";\n}\n.glyphicon-export:before {\n content: \"\\e170\";\n}\n.glyphicon-send:before {\n content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n content: \"\\e179\";\n}\n.glyphicon-header:before {\n content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n content: \"\\e183\";\n}\n.glyphicon-tower:before {\n content: \"\\e184\";\n}\n.glyphicon-stats:before {\n content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n content: \"\\e200\";\n}\n* {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n*:before,\n*:after {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.42857143;\n color: #333333;\n background-color: #ffffff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\na {\n color: #337ab7;\n text-decoration: none;\n}\na:hover,\na:focus {\n color: #23527c;\n text-decoration: underline;\n}\na:focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\nfigure {\n margin: 0;\n}\nimg {\n vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n display: block;\n max-width: 100%;\n height: auto;\n}\n.img-rounded {\n border-radius: 6px;\n}\n.img-thumbnail {\n padding: 4px;\n line-height: 1.42857143;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 4px;\n -webkit-transition: all 0.2s ease-in-out;\n -o-transition: all 0.2s ease-in-out;\n transition: all 0.2s ease-in-out;\n display: inline-block;\n max-width: 100%;\n height: auto;\n}\n.img-circle {\n border-radius: 50%;\n}\nhr {\n margin-top: 20px;\n margin-bottom: 20px;\n border: 0;\n border-top: 1px solid #eeeeee;\n}\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n font-weight: normal;\n line-height: 1;\n color: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n margin-top: 20px;\n margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n margin-top: 10px;\n margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n font-size: 75%;\n}\nh1,\n.h1 {\n font-size: 36px;\n}\nh2,\n.h2 {\n font-size: 30px;\n}\nh3,\n.h3 {\n font-size: 24px;\n}\nh4,\n.h4 {\n font-size: 18px;\n}\nh5,\n.h5 {\n font-size: 14px;\n}\nh6,\n.h6 {\n font-size: 12px;\n}\np {\n margin: 0 0 10px;\n}\n.lead {\n margin-bottom: 20px;\n font-size: 16px;\n font-weight: 300;\n line-height: 1.4;\n}\n@media (min-width: 768px) {\n .lead {\n font-size: 21px;\n }\n}\nsmall,\n.small {\n font-size: 85%;\n}\nmark,\n.mark {\n background-color: #fcf8e3;\n padding: .2em;\n}\n.text-left {\n text-align: left;\n}\n.text-right {\n text-align: right;\n}\n.text-center {\n text-align: center;\n}\n.text-justify {\n text-align: justify;\n}\n.text-nowrap {\n white-space: nowrap;\n}\n.text-lowercase {\n text-transform: lowercase;\n}\n.text-uppercase {\n text-transform: uppercase;\n}\n.text-capitalize {\n text-transform: capitalize;\n}\n.text-muted {\n color: #777777;\n}\n.text-primary {\n color: #337ab7;\n}\na.text-primary:hover {\n color: #286090;\n}\n.text-success {\n color: #3c763d;\n}\na.text-success:hover {\n color: #2b542c;\n}\n.text-info {\n color: #31708f;\n}\na.text-info:hover {\n color: #245269;\n}\n.text-warning {\n color: #8a6d3b;\n}\na.text-warning:hover {\n color: #66512c;\n}\n.text-danger {\n color: #a94442;\n}\na.text-danger:hover {\n color: #843534;\n}\n.bg-primary {\n color: #fff;\n background-color: #337ab7;\n}\na.bg-primary:hover {\n background-color: #286090;\n}\n.bg-success {\n background-color: #dff0d8;\n}\na.bg-success:hover {\n background-color: #c1e2b3;\n}\n.bg-info {\n background-color: #d9edf7;\n}\na.bg-info:hover {\n background-color: #afd9ee;\n}\n.bg-warning {\n background-color: #fcf8e3;\n}\na.bg-warning:hover {\n background-color: #f7ecb5;\n}\n.bg-danger {\n background-color: #f2dede;\n}\na.bg-danger:hover {\n background-color: #e4b9b9;\n}\n.page-header {\n padding-bottom: 9px;\n margin: 40px 0 20px;\n border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n margin-top: 0;\n margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n margin-bottom: 0;\n}\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n.list-inline {\n padding-left: 0;\n list-style: none;\n margin-left: -5px;\n}\n.list-inline > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n}\ndl {\n margin-top: 0;\n margin-bottom: 20px;\n}\ndt,\ndd {\n line-height: 1.42857143;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0;\n}\n@media (min-width: 768px) {\n .dl-horizontal dt {\n float: left;\n width: 160px;\n clear: left;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .dl-horizontal dd {\n margin-left: 180px;\n }\n}\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted #777777;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\nblockquote {\n padding: 10px 20px;\n margin: 0 0 20px;\n font-size: 17.5px;\n border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n display: block;\n font-size: 80%;\n line-height: 1.42857143;\n color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid #eeeeee;\n border-left: 0;\n text-align: right;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n content: '\\00A0 \\2014';\n}\naddress {\n margin-bottom: 20px;\n font-style: normal;\n line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: #c7254e;\n background-color: #f9f2f4;\n border-radius: 4px;\n}\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: #ffffff;\n background-color: #333333;\n border-radius: 3px;\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n}\npre {\n display: block;\n padding: 9.5px;\n margin: 0 0 10px;\n font-size: 13px;\n line-height: 1.42857143;\n word-break: break-all;\n word-wrap: break-word;\n color: #333333;\n background-color: #f5f5f5;\n border: 1px solid #cccccc;\n border-radius: 4px;\n}\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n}\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n.container {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n@media (min-width: 768px) {\n .container {\n width: 750px;\n }\n}\n@media (min-width: 992px) {\n .container {\n width: 970px;\n }\n}\n@media (min-width: 1200px) {\n .container {\n width: 1170px;\n }\n}\n.container-fluid {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n.row {\n margin-left: -15px;\n margin-right: -15px;\n}\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n position: relative;\n min-height: 1px;\n padding-left: 15px;\n padding-right: 15px;\n}\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n float: left;\n}\n.col-xs-12 {\n width: 100%;\n}\n.col-xs-11 {\n width: 91.66666667%;\n}\n.col-xs-10 {\n width: 83.33333333%;\n}\n.col-xs-9 {\n width: 75%;\n}\n.col-xs-8 {\n width: 66.66666667%;\n}\n.col-xs-7 {\n width: 58.33333333%;\n}\n.col-xs-6 {\n width: 50%;\n}\n.col-xs-5 {\n width: 41.66666667%;\n}\n.col-xs-4 {\n width: 33.33333333%;\n}\n.col-xs-3 {\n width: 25%;\n}\n.col-xs-2 {\n width: 16.66666667%;\n}\n.col-xs-1 {\n width: 8.33333333%;\n}\n.col-xs-pull-12 {\n right: 100%;\n}\n.col-xs-pull-11 {\n right: 91.66666667%;\n}\n.col-xs-pull-10 {\n right: 83.33333333%;\n}\n.col-xs-pull-9 {\n right: 75%;\n}\n.col-xs-pull-8 {\n right: 66.66666667%;\n}\n.col-xs-pull-7 {\n right: 58.33333333%;\n}\n.col-xs-pull-6 {\n right: 50%;\n}\n.col-xs-pull-5 {\n right: 41.66666667%;\n}\n.col-xs-pull-4 {\n right: 33.33333333%;\n}\n.col-xs-pull-3 {\n right: 25%;\n}\n.col-xs-pull-2 {\n right: 16.66666667%;\n}\n.col-xs-pull-1 {\n right: 8.33333333%;\n}\n.col-xs-pull-0 {\n right: auto;\n}\n.col-xs-push-12 {\n left: 100%;\n}\n.col-xs-push-11 {\n left: 91.66666667%;\n}\n.col-xs-push-10 {\n left: 83.33333333%;\n}\n.col-xs-push-9 {\n left: 75%;\n}\n.col-xs-push-8 {\n left: 66.66666667%;\n}\n.col-xs-push-7 {\n left: 58.33333333%;\n}\n.col-xs-push-6 {\n left: 50%;\n}\n.col-xs-push-5 {\n left: 41.66666667%;\n}\n.col-xs-push-4 {\n left: 33.33333333%;\n}\n.col-xs-push-3 {\n left: 25%;\n}\n.col-xs-push-2 {\n left: 16.66666667%;\n}\n.col-xs-push-1 {\n left: 8.33333333%;\n}\n.col-xs-push-0 {\n left: auto;\n}\n.col-xs-offset-12 {\n margin-left: 100%;\n}\n.col-xs-offset-11 {\n margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n margin-left: 75%;\n}\n.col-xs-offset-8 {\n margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n margin-left: 50%;\n}\n.col-xs-offset-5 {\n margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n margin-left: 25%;\n}\n.col-xs-offset-2 {\n margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n margin-left: 0%;\n}\n@media (min-width: 768px) {\n .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {\n float: left;\n }\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666667%;\n }\n .col-sm-10 {\n width: 83.33333333%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666667%;\n }\n .col-sm-7 {\n width: 58.33333333%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666667%;\n }\n .col-sm-4 {\n width: 33.33333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.66666667%;\n }\n .col-sm-1 {\n width: 8.33333333%;\n }\n .col-sm-pull-12 {\n right: 100%;\n }\n .col-sm-pull-11 {\n right: 91.66666667%;\n }\n .col-sm-pull-10 {\n right: 83.33333333%;\n }\n .col-sm-pull-9 {\n right: 75%;\n }\n .col-sm-pull-8 {\n right: 66.66666667%;\n }\n .col-sm-pull-7 {\n right: 58.33333333%;\n }\n .col-sm-pull-6 {\n right: 50%;\n }\n .col-sm-pull-5 {\n right: 41.66666667%;\n }\n .col-sm-pull-4 {\n right: 33.33333333%;\n }\n .col-sm-pull-3 {\n right: 25%;\n }\n .col-sm-pull-2 {\n right: 16.66666667%;\n }\n .col-sm-pull-1 {\n right: 8.33333333%;\n }\n .col-sm-pull-0 {\n right: auto;\n }\n .col-sm-push-12 {\n left: 100%;\n }\n .col-sm-push-11 {\n left: 91.66666667%;\n }\n .col-sm-push-10 {\n left: 83.33333333%;\n }\n .col-sm-push-9 {\n left: 75%;\n }\n .col-sm-push-8 {\n left: 66.66666667%;\n }\n .col-sm-push-7 {\n left: 58.33333333%;\n }\n .col-sm-push-6 {\n left: 50%;\n }\n .col-sm-push-5 {\n left: 41.66666667%;\n }\n .col-sm-push-4 {\n left: 33.33333333%;\n }\n .col-sm-push-3 {\n left: 25%;\n }\n .col-sm-push-2 {\n left: 16.66666667%;\n }\n .col-sm-push-1 {\n left: 8.33333333%;\n }\n .col-sm-push-0 {\n left: auto;\n }\n .col-sm-offset-12 {\n margin-left: 100%;\n }\n .col-sm-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-sm-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-sm-offset-9 {\n margin-left: 75%;\n }\n .col-sm-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-sm-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-sm-offset-6 {\n margin-left: 50%;\n }\n .col-sm-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-sm-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-sm-offset-3 {\n margin-left: 25%;\n }\n .col-sm-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-sm-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-sm-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 992px) {\n .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {\n float: left;\n }\n .col-md-12 {\n width: 100%;\n }\n .col-md-11 {\n width: 91.66666667%;\n }\n .col-md-10 {\n width: 83.33333333%;\n }\n .col-md-9 {\n width: 75%;\n }\n .col-md-8 {\n width: 66.66666667%;\n }\n .col-md-7 {\n width: 58.33333333%;\n }\n .col-md-6 {\n width: 50%;\n }\n .col-md-5 {\n width: 41.66666667%;\n }\n .col-md-4 {\n width: 33.33333333%;\n }\n .col-md-3 {\n width: 25%;\n }\n .col-md-2 {\n width: 16.66666667%;\n }\n .col-md-1 {\n width: 8.33333333%;\n }\n .col-md-pull-12 {\n right: 100%;\n }\n .col-md-pull-11 {\n right: 91.66666667%;\n }\n .col-md-pull-10 {\n right: 83.33333333%;\n }\n .col-md-pull-9 {\n right: 75%;\n }\n .col-md-pull-8 {\n right: 66.66666667%;\n }\n .col-md-pull-7 {\n right: 58.33333333%;\n }\n .col-md-pull-6 {\n right: 50%;\n }\n .col-md-pull-5 {\n right: 41.66666667%;\n }\n .col-md-pull-4 {\n right: 33.33333333%;\n }\n .col-md-pull-3 {\n right: 25%;\n }\n .col-md-pull-2 {\n right: 16.66666667%;\n }\n .col-md-pull-1 {\n right: 8.33333333%;\n }\n .col-md-pull-0 {\n right: auto;\n }\n .col-md-push-12 {\n left: 100%;\n }\n .col-md-push-11 {\n left: 91.66666667%;\n }\n .col-md-push-10 {\n left: 83.33333333%;\n }\n .col-md-push-9 {\n left: 75%;\n }\n .col-md-push-8 {\n left: 66.66666667%;\n }\n .col-md-push-7 {\n left: 58.33333333%;\n }\n .col-md-push-6 {\n left: 50%;\n }\n .col-md-push-5 {\n left: 41.66666667%;\n }\n .col-md-push-4 {\n left: 33.33333333%;\n }\n .col-md-push-3 {\n left: 25%;\n }\n .col-md-push-2 {\n left: 16.66666667%;\n }\n .col-md-push-1 {\n left: 8.33333333%;\n }\n .col-md-push-0 {\n left: auto;\n }\n .col-md-offset-12 {\n margin-left: 100%;\n }\n .col-md-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-md-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-md-offset-9 {\n margin-left: 75%;\n }\n .col-md-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-md-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-md-offset-6 {\n margin-left: 50%;\n }\n .col-md-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-md-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-md-offset-3 {\n margin-left: 25%;\n }\n .col-md-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-md-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-md-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 1200px) {\n .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {\n float: left;\n }\n .col-lg-12 {\n width: 100%;\n }\n .col-lg-11 {\n width: 91.66666667%;\n }\n .col-lg-10 {\n width: 83.33333333%;\n }\n .col-lg-9 {\n width: 75%;\n }\n .col-lg-8 {\n width: 66.66666667%;\n }\n .col-lg-7 {\n width: 58.33333333%;\n }\n .col-lg-6 {\n width: 50%;\n }\n .col-lg-5 {\n width: 41.66666667%;\n }\n .col-lg-4 {\n width: 33.33333333%;\n }\n .col-lg-3 {\n width: 25%;\n }\n .col-lg-2 {\n width: 16.66666667%;\n }\n .col-lg-1 {\n width: 8.33333333%;\n }\n .col-lg-pull-12 {\n right: 100%;\n }\n .col-lg-pull-11 {\n right: 91.66666667%;\n }\n .col-lg-pull-10 {\n right: 83.33333333%;\n }\n .col-lg-pull-9 {\n right: 75%;\n }\n .col-lg-pull-8 {\n right: 66.66666667%;\n }\n .col-lg-pull-7 {\n right: 58.33333333%;\n }\n .col-lg-pull-6 {\n right: 50%;\n }\n .col-lg-pull-5 {\n right: 41.66666667%;\n }\n .col-lg-pull-4 {\n right: 33.33333333%;\n }\n .col-lg-pull-3 {\n right: 25%;\n }\n .col-lg-pull-2 {\n right: 16.66666667%;\n }\n .col-lg-pull-1 {\n right: 8.33333333%;\n }\n .col-lg-pull-0 {\n right: auto;\n }\n .col-lg-push-12 {\n left: 100%;\n }\n .col-lg-push-11 {\n left: 91.66666667%;\n }\n .col-lg-push-10 {\n left: 83.33333333%;\n }\n .col-lg-push-9 {\n left: 75%;\n }\n .col-lg-push-8 {\n left: 66.66666667%;\n }\n .col-lg-push-7 {\n left: 58.33333333%;\n }\n .col-lg-push-6 {\n left: 50%;\n }\n .col-lg-push-5 {\n left: 41.66666667%;\n }\n .col-lg-push-4 {\n left: 33.33333333%;\n }\n .col-lg-push-3 {\n left: 25%;\n }\n .col-lg-push-2 {\n left: 16.66666667%;\n }\n .col-lg-push-1 {\n left: 8.33333333%;\n }\n .col-lg-push-0 {\n left: auto;\n }\n .col-lg-offset-12 {\n margin-left: 100%;\n }\n .col-lg-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-lg-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-lg-offset-9 {\n margin-left: 75%;\n }\n .col-lg-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-lg-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-lg-offset-6 {\n margin-left: 50%;\n }\n .col-lg-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-lg-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-lg-offset-3 {\n margin-left: 25%;\n }\n .col-lg-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-lg-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-lg-offset-0 {\n margin-left: 0%;\n }\n}\ntable {\n background-color: transparent;\n}\ncaption {\n padding-top: 8px;\n padding-bottom: 8px;\n color: #777777;\n text-align: left;\n}\nth {\n text-align: left;\n}\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n padding: 8px;\n line-height: 1.42857143;\n vertical-align: top;\n border-top: 1px solid #dddddd;\n}\n.table > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid #dddddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n border-top: 0;\n}\n.table > tbody + tbody {\n border-top: 2px solid #dddddd;\n}\n.table .table {\n background-color: #ffffff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n padding: 5px;\n}\n.table-bordered {\n border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-child(odd) {\n background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-column;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-cell;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n background-color: #ebcccc;\n}\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%;\n}\n@media screen and (max-width: 767px) {\n .table-responsive {\n width: 100%;\n margin-bottom: 15px;\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid #dddddd;\n }\n .table-responsive > .table {\n margin-bottom: 0;\n }\n .table-responsive > .table > thead > tr > th,\n .table-responsive > .table > tbody > tr > th,\n .table-responsive > .table > tfoot > tr > th,\n .table-responsive > .table > thead > tr > td,\n .table-responsive > .table > tbody > tr > td,\n .table-responsive > .table > tfoot > tr > td {\n white-space: nowrap;\n }\n .table-responsive > .table-bordered {\n border: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:first-child,\n .table-responsive > .table-bordered > tbody > tr > th:first-child,\n .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n .table-responsive > .table-bordered > thead > tr > td:first-child,\n .table-responsive > .table-bordered > tbody > tr > td:first-child,\n .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:last-child,\n .table-responsive > .table-bordered > tbody > tr > th:last-child,\n .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n .table-responsive > .table-bordered > thead > tr > td:last-child,\n .table-responsive > .table-bordered > tbody > tr > td:last-child,\n .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n }\n .table-responsive > .table-bordered > tbody > tr:last-child > th,\n .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n .table-responsive > .table-bordered > tbody > tr:last-child > td,\n .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n border-bottom: 0;\n }\n}\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n min-width: 0;\n}\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: 20px;\n font-size: 21px;\n line-height: inherit;\n color: #333333;\n border: 0;\n border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n display: inline-block;\n max-width: 100%;\n margin-bottom: 5px;\n font-weight: bold;\n}\ninput[type=\"search\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9;\n line-height: normal;\n}\ninput[type=\"file\"] {\n display: block;\n}\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\nselect[multiple],\nselect[size] {\n height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\noutput {\n display: block;\n padding-top: 7px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n}\n.form-control {\n display: block;\n width: 100%;\n height: 34px;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n background-color: #ffffff;\n background-image: none;\n border: 1px solid #cccccc;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n border-color: #66afe9;\n outline: 0;\n -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n color: #999999;\n opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n color: #999999;\n}\n.form-control::-webkit-input-placeholder {\n color: #999999;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n cursor: not-allowed;\n background-color: #eeeeee;\n opacity: 1;\n}\ntextarea.form-control {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"],\n input[type=\"time\"],\n input[type=\"datetime-local\"],\n input[type=\"month\"] {\n line-height: 34px;\n }\n input[type=\"date\"].input-sm,\n input[type=\"time\"].input-sm,\n input[type=\"datetime-local\"].input-sm,\n input[type=\"month\"].input-sm {\n line-height: 30px;\n }\n input[type=\"date\"].input-lg,\n input[type=\"time\"].input-lg,\n input[type=\"datetime-local\"].input-lg,\n input[type=\"month\"].input-lg {\n line-height: 46px;\n }\n}\n.form-group {\n margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n min-height: 20px;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-left: -20px;\n margin-top: 4px \\9;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n cursor: not-allowed;\n}\n.form-control-static {\n padding-top: 7px;\n padding-bottom: 7px;\n margin-bottom: 0;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n padding-left: 0;\n padding-right: 0;\n}\n.input-sm,\n.form-group-sm .form-control {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-sm,\nselect.form-group-sm .form-control {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-sm,\ntextarea.form-group-sm .form-control,\nselect[multiple].input-sm,\nselect[multiple].form-group-sm .form-control {\n height: auto;\n}\n.input-lg,\n.form-group-lg .form-control {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.33;\n border-radius: 6px;\n}\nselect.input-lg,\nselect.form-group-lg .form-control {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-lg,\ntextarea.form-group-lg .form-control,\nselect[multiple].input-lg,\nselect[multiple].form-group-lg .form-control {\n height: auto;\n}\n.has-feedback {\n position: relative;\n}\n.has-feedback .form-control {\n padding-right: 42.5px;\n}\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback {\n width: 46px;\n height: 46px;\n line-height: 46px;\n}\n.input-sm + .form-control-feedback {\n width: 30px;\n height: 30px;\n line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n color: #3c763d;\n}\n.has-success .form-control {\n border-color: #3c763d;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n border-color: #2b542c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n color: #3c763d;\n border-color: #3c763d;\n background-color: #dff0d8;\n}\n.has-success .form-control-feedback {\n color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n color: #8a6d3b;\n}\n.has-warning .form-control {\n border-color: #8a6d3b;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n border-color: #66512c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n color: #8a6d3b;\n border-color: #8a6d3b;\n background-color: #fcf8e3;\n}\n.has-warning .form-control-feedback {\n color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n color: #a94442;\n}\n.has-error .form-control {\n border-color: #a94442;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n border-color: #843534;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n color: #a94442;\n border-color: #a94442;\n background-color: #f2dede;\n}\n.has-error .form-control-feedback {\n color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n top: 0;\n}\n.help-block {\n display: block;\n margin-top: 5px;\n margin-bottom: 10px;\n color: #737373;\n}\n@media (min-width: 768px) {\n .form-inline .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-static {\n display: inline-block;\n }\n .form-inline .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .form-inline .input-group .input-group-addon,\n .form-inline .input-group .input-group-btn,\n .form-inline .input-group .form-control {\n width: auto;\n }\n .form-inline .input-group > .form-control {\n width: 100%;\n }\n .form-inline .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio,\n .form-inline .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio label,\n .form-inline .checkbox label {\n padding-left: 0;\n }\n .form-inline .radio input[type=\"radio\"],\n .form-inline .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n margin-top: 0;\n margin-bottom: 0;\n padding-top: 7px;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n min-height: 27px;\n}\n.form-horizontal .form-group {\n margin-left: -15px;\n margin-right: -15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .control-label {\n text-align: right;\n margin-bottom: 0;\n padding-top: 7px;\n }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n right: 15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-lg .control-label {\n padding-top: 14.3px;\n }\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-sm .control-label {\n padding-top: 6px;\n }\n}\n.btn {\n display: inline-block;\n margin-bottom: 0;\n font-weight: normal;\n text-align: center;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none;\n border: 1px solid transparent;\n white-space: nowrap;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n border-radius: 4px;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n color: #333333;\n text-decoration: none;\n}\n.btn:active,\n.btn.active {\n outline: 0;\n background-image: none;\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n cursor: not-allowed;\n pointer-events: none;\n opacity: 0.65;\n filter: alpha(opacity=65);\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-default {\n color: #333333;\n background-color: #ffffff;\n border-color: #cccccc;\n}\n.btn-default:hover,\n.btn-default:focus,\n.btn-default.focus,\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n color: #333333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n background-image: none;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n background-color: #ffffff;\n border-color: #cccccc;\n}\n.btn-default .badge {\n color: #ffffff;\n background-color: #333333;\n}\n.btn-primary {\n color: #ffffff;\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary:hover,\n.btn-primary:focus,\n.btn-primary.focus,\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n color: #ffffff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n background-image: none;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary .badge {\n color: #337ab7;\n background-color: #ffffff;\n}\n.btn-success {\n color: #ffffff;\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success:hover,\n.btn-success:focus,\n.btn-success.focus,\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n color: #ffffff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n background-image: none;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success .badge {\n color: #5cb85c;\n background-color: #ffffff;\n}\n.btn-info {\n color: #ffffff;\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info:hover,\n.btn-info:focus,\n.btn-info.focus,\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n color: #ffffff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n background-image: none;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info .badge {\n color: #5bc0de;\n background-color: #ffffff;\n}\n.btn-warning {\n color: #ffffff;\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning:hover,\n.btn-warning:focus,\n.btn-warning.focus,\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n color: #ffffff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n background-image: none;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning .badge {\n color: #f0ad4e;\n background-color: #ffffff;\n}\n.btn-danger {\n color: #ffffff;\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger:hover,\n.btn-danger:focus,\n.btn-danger.focus,\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n color: #ffffff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n background-image: none;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger .badge {\n color: #d9534f;\n background-color: #ffffff;\n}\n.btn-link {\n color: #337ab7;\n font-weight: normal;\n border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n background-color: transparent;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n color: #23527c;\n text-decoration: underline;\n background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n color: #777777;\n text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.33;\n border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n padding: 1px 5px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-block {\n display: block;\n width: 100%;\n}\n.btn-block + .btn-block {\n margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n.fade {\n opacity: 0;\n -webkit-transition: opacity 0.15s linear;\n -o-transition: opacity 0.15s linear;\n transition: opacity 0.15s linear;\n}\n.fade.in {\n opacity: 1;\n}\n.collapse {\n display: none;\n visibility: hidden;\n}\n.collapse.in {\n display: block;\n visibility: visible;\n}\ntr.collapse.in {\n display: table-row;\n}\ntbody.collapse.in {\n display: table-row-group;\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n -webkit-transition-property: height, visibility;\n transition-property: height, visibility;\n -webkit-transition-duration: 0.35s;\n transition-duration: 0.35s;\n -webkit-transition-timing-function: ease;\n transition-timing-function: ease;\n}\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: 4px solid;\n border-right: 4px solid transparent;\n border-left: 4px solid transparent;\n}\n.dropdown {\n position: relative;\n}\n.dropdown-toggle:focus {\n outline: 0;\n}\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0;\n list-style: none;\n font-size: 14px;\n text-align: left;\n background-color: #ffffff;\n border: 1px solid #cccccc;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 4px;\n -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n background-clip: padding-box;\n}\n.dropdown-menu.pull-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu .divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: 1.42857143;\n color: #333333;\n white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n text-decoration: none;\n color: #262626;\n background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n color: #ffffff;\n text-decoration: none;\n outline: 0;\n background-color: #337ab7;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n color: #777777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n cursor: not-allowed;\n}\n.open > .dropdown-menu {\n display: block;\n}\n.open > a {\n outline: 0;\n}\n.dropdown-menu-right {\n left: auto;\n right: 0;\n}\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: 12px;\n line-height: 1.42857143;\n color: #777777;\n white-space: nowrap;\n}\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: 990;\n}\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n border-top: 0;\n border-bottom: 4px solid;\n content: \"\";\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 1px;\n}\n@media (min-width: 768px) {\n .navbar-right .dropdown-menu {\n left: auto;\n right: 0;\n }\n .navbar-right .dropdown-menu-left {\n left: 0;\n right: auto;\n }\n}\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n margin-left: -1px;\n}\n.btn-toolbar {\n margin-left: -5px;\n}\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child > .btn:last-child,\n.btn-group > .btn-group:first-child > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn-group:last-child > .btn:first-child {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n.btn-group.open .dropdown-toggle {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn .caret {\n margin-left: 0;\n}\n.btn-lg .caret {\n border-width: 5px 5px 0;\n border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-bottom-left-radius: 4px;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.input-group {\n position: relative;\n display: table;\n border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n}\n.input-group .form-control {\n position: relative;\n z-index: 2;\n float: left;\n width: 100%;\n margin-bottom: 0;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.33;\n border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle;\n}\n.input-group-addon {\n padding: 6px 12px;\n font-size: 14px;\n font-weight: normal;\n line-height: 1;\n color: #555555;\n text-align: center;\n background-color: #eeeeee;\n border: 1px solid #cccccc;\n border-radius: 4px;\n}\n.input-group-addon.input-sm {\n padding: 5px 10px;\n font-size: 12px;\n border-radius: 3px;\n}\n.input-group-addon.input-lg {\n padding: 10px 16px;\n font-size: 18px;\n border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n.input-group-btn > .btn {\n position: relative;\n}\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n margin-left: -1px;\n}\n.nav {\n margin-bottom: 0;\n padding-left: 0;\n list-style: none;\n}\n.nav > li {\n position: relative;\n display: block;\n}\n.nav > li > a {\n position: relative;\n display: block;\n padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n color: #777777;\n text-decoration: none;\n background-color: transparent;\n cursor: not-allowed;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n background-color: #eeeeee;\n border-color: #337ab7;\n}\n.nav .nav-divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.nav > li > a > img {\n max-width: none;\n}\n.nav-tabs {\n border-bottom: 1px solid #dddddd;\n}\n.nav-tabs > li {\n float: left;\n margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n margin-right: 2px;\n line-height: 1.42857143;\n border: 1px solid transparent;\n border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n border-color: #eeeeee #eeeeee #dddddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n color: #555555;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-bottom-color: transparent;\n cursor: default;\n}\n.nav-tabs.nav-justified {\n width: 100%;\n border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n float: none;\n}\n.nav-tabs.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-tabs.nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs.nav-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li > a {\n border-bottom: 1px solid #dddddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs.nav-justified > .active > a,\n .nav-tabs.nav-justified > .active > a:hover,\n .nav-tabs.nav-justified > .active > a:focus {\n border-bottom-color: #ffffff;\n }\n}\n.nav-pills > li {\n float: left;\n}\n.nav-pills > li > a {\n border-radius: 4px;\n}\n.nav-pills > li + li {\n margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n color: #ffffff;\n background-color: #337ab7;\n}\n.nav-stacked > li {\n float: none;\n}\n.nav-stacked > li + li {\n margin-top: 2px;\n margin-left: 0;\n}\n.nav-justified {\n width: 100%;\n}\n.nav-justified > li {\n float: none;\n}\n.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs-justified {\n border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n .nav-tabs-justified > li > a {\n border-bottom: 1px solid #dddddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs-justified > .active > a,\n .nav-tabs-justified > .active > a:hover,\n .nav-tabs-justified > .active > a:focus {\n border-bottom-color: #ffffff;\n }\n}\n.tab-content > .tab-pane {\n display: none;\n visibility: hidden;\n}\n.tab-content > .active {\n display: block;\n visibility: visible;\n}\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar {\n position: relative;\n min-height: 50px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n .navbar {\n border-radius: 4px;\n }\n}\n@media (min-width: 768px) {\n .navbar-header {\n float: left;\n }\n}\n.navbar-collapse {\n overflow-x: visible;\n padding-right: 15px;\n padding-left: 15px;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n overflow-y: auto;\n}\n@media (min-width: 768px) {\n .navbar-collapse {\n width: auto;\n border-top: 0;\n box-shadow: none;\n }\n .navbar-collapse.collapse {\n display: block !important;\n visibility: visible !important;\n height: auto !important;\n padding-bottom: 0;\n overflow: visible !important;\n }\n .navbar-collapse.in {\n overflow-y: visible;\n }\n .navbar-fixed-top .navbar-collapse,\n .navbar-static-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n padding-left: 0;\n padding-right: 0;\n }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n .navbar-fixed-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n max-height: 200px;\n }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .container > .navbar-header,\n .container-fluid > .navbar-header,\n .container > .navbar-collapse,\n .container-fluid > .navbar-collapse {\n margin-right: 0;\n margin-left: 0;\n }\n}\n.navbar-static-top {\n z-index: 1000;\n border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n .navbar-static-top {\n border-radius: 0;\n }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n@media (min-width: 768px) {\n .navbar-fixed-top,\n .navbar-fixed-bottom {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0;\n border-width: 1px 0 0;\n}\n.navbar-brand {\n float: left;\n padding: 15px 15px;\n font-size: 18px;\n line-height: 20px;\n height: 50px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n text-decoration: none;\n}\n.navbar-brand > img {\n display: block;\n}\n@media (min-width: 768px) {\n .navbar > .container .navbar-brand,\n .navbar > .container-fluid .navbar-brand {\n margin-left: -15px;\n }\n}\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: 15px;\n padding: 9px 10px;\n margin-top: 8px;\n margin-bottom: 8px;\n background-color: transparent;\n background-image: none;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.navbar-toggle:focus {\n outline: 0;\n}\n.navbar-toggle .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n margin-top: 4px;\n}\n@media (min-width: 768px) {\n .navbar-toggle {\n display: none;\n }\n}\n.navbar-nav {\n margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: 20px;\n}\n@media (max-width: 767px) {\n .navbar-nav .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n }\n .navbar-nav .open .dropdown-menu > li > a,\n .navbar-nav .open .dropdown-menu .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n .navbar-nav .open .dropdown-menu > li > a {\n line-height: 20px;\n }\n .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-nav .open .dropdown-menu > li > a:focus {\n background-image: none;\n }\n}\n@media (min-width: 768px) {\n .navbar-nav {\n float: left;\n margin: 0;\n }\n .navbar-nav > li {\n float: left;\n }\n .navbar-nav > li > a {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n}\n.navbar-form {\n margin-left: -15px;\n margin-right: -15px;\n padding: 10px 15px;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n margin-top: 8px;\n margin-bottom: 8px;\n}\n@media (min-width: 768px) {\n .navbar-form .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .navbar-form .form-control-static {\n display: inline-block;\n }\n .navbar-form .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .navbar-form .input-group .input-group-addon,\n .navbar-form .input-group .input-group-btn,\n .navbar-form .input-group .form-control {\n width: auto;\n }\n .navbar-form .input-group > .form-control {\n width: 100%;\n }\n .navbar-form .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio,\n .navbar-form .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio label,\n .navbar-form .checkbox label {\n padding-left: 0;\n }\n .navbar-form .radio input[type=\"radio\"],\n .navbar-form .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .navbar-form .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n@media (max-width: 767px) {\n .navbar-form .form-group {\n margin-bottom: 5px;\n }\n .navbar-form .form-group:last-child {\n margin-bottom: 0;\n }\n}\n@media (min-width: 768px) {\n .navbar-form {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n}\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.navbar-btn {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n margin-top: 14px;\n margin-bottom: 14px;\n}\n.navbar-text {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n .navbar-text {\n float: left;\n margin-left: 15px;\n margin-right: 15px;\n }\n}\n@media (min-width: 768px) {\n .navbar-left {\n float: left !important;\n }\n .navbar-right {\n float: right !important;\n margin-right: -15px;\n }\n .navbar-right ~ .navbar-right {\n margin-right: 0;\n }\n}\n.navbar-default {\n background-color: #f8f8f8;\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n color: #777777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n color: #5e5e5e;\n background-color: transparent;\n}\n.navbar-default .navbar-text {\n color: #777777;\n}\n.navbar-default .navbar-nav > li > a {\n color: #777777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n color: #333333;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n color: #555555;\n background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n color: #cccccc;\n background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n border-color: #dddddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n background-color: #dddddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n background-color: #888888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n background-color: #e7e7e7;\n color: #555555;\n}\n@media (max-width: 767px) {\n .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n color: #777777;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #333333;\n background-color: transparent;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #555555;\n background-color: #e7e7e7;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #cccccc;\n background-color: transparent;\n }\n}\n.navbar-default .navbar-link {\n color: #777777;\n}\n.navbar-default .navbar-link:hover {\n color: #333333;\n}\n.navbar-default .btn-link {\n color: #777777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n color: #333333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n color: #cccccc;\n}\n.navbar-inverse {\n background-color: #222222;\n border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n color: #ffffff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n color: #ffffff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n color: #ffffff;\n background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n color: #444444;\n background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n border-color: #333333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n background-color: #333333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n background-color: #ffffff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n background-color: #080808;\n color: #ffffff;\n}\n@media (max-width: 767px) {\n .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n border-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n color: #9d9d9d;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #ffffff;\n background-color: transparent;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #ffffff;\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #444444;\n background-color: transparent;\n }\n}\n.navbar-inverse .navbar-link {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n color: #ffffff;\n}\n.navbar-inverse .btn-link {\n color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n color: #ffffff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n color: #444444;\n}\n.breadcrumb {\n padding: 8px 15px;\n margin-bottom: 20px;\n list-style: none;\n background-color: #f5f5f5;\n border-radius: 4px;\n}\n.breadcrumb > li {\n display: inline-block;\n}\n.breadcrumb > li + li:before {\n content: \"/\\00a0\";\n padding: 0 5px;\n color: #cccccc;\n}\n.breadcrumb > .active {\n color: #777777;\n}\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: 20px 0;\n border-radius: 4px;\n}\n.pagination > li {\n display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n position: relative;\n float: left;\n padding: 6px 12px;\n line-height: 1.42857143;\n text-decoration: none;\n color: #337ab7;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n margin-left: -1px;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n margin-left: 0;\n border-bottom-left-radius: 4px;\n border-top-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n border-bottom-right-radius: 4px;\n border-top-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n color: #23527c;\n background-color: #eeeeee;\n border-color: #dddddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n z-index: 2;\n color: #ffffff;\n background-color: #337ab7;\n border-color: #337ab7;\n cursor: default;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n color: #777777;\n background-color: #ffffff;\n border-color: #dddddd;\n cursor: not-allowed;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n padding: 10px 16px;\n font-size: 18px;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n border-bottom-left-radius: 6px;\n border-top-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n border-bottom-right-radius: 6px;\n border-top-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n padding: 5px 10px;\n font-size: 12px;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n border-bottom-left-radius: 3px;\n border-top-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n border-bottom-right-radius: 3px;\n border-top-right-radius: 3px;\n}\n.pager {\n padding-left: 0;\n margin: 20px 0;\n list-style: none;\n text-align: center;\n}\n.pager li {\n display: inline;\n}\n.pager li > a,\n.pager li > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n color: #777777;\n background-color: #ffffff;\n cursor: not-allowed;\n}\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: #ffffff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n color: #ffffff;\n text-decoration: none;\n cursor: pointer;\n}\n.label:empty {\n display: none;\n}\n.btn .label {\n position: relative;\n top: -1px;\n}\n.label-default {\n background-color: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n background-color: #5e5e5e;\n}\n.label-primary {\n background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n background-color: #286090;\n}\n.label-success {\n background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n background-color: #449d44;\n}\n.label-info {\n background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n background-color: #31b0d5;\n}\n.label-warning {\n background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n background-color: #ec971f;\n}\n.label-danger {\n background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n background-color: #c9302c;\n}\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: 12px;\n font-weight: bold;\n color: #ffffff;\n line-height: 1;\n vertical-align: baseline;\n white-space: nowrap;\n text-align: center;\n background-color: #777777;\n border-radius: 10px;\n}\n.badge:empty {\n display: none;\n}\n.btn .badge {\n position: relative;\n top: -1px;\n}\n.btn-xs .badge {\n top: 0;\n padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n color: #ffffff;\n text-decoration: none;\n cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: #337ab7;\n background-color: #ffffff;\n}\n.list-group-item > .badge {\n float: right;\n}\n.list-group-item > .badge + .badge {\n margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n.jumbotron {\n padding: 30px 15px;\n margin-bottom: 30px;\n color: inherit;\n background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n color: inherit;\n}\n.jumbotron p {\n margin-bottom: 15px;\n font-size: 21px;\n font-weight: 200;\n}\n.jumbotron > hr {\n border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n border-radius: 6px;\n}\n.jumbotron .container {\n max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n .jumbotron {\n padding: 48px 0;\n }\n .container .jumbotron,\n .container-fluid .jumbotron {\n padding-left: 60px;\n padding-right: 60px;\n }\n .jumbotron h1,\n .jumbotron .h1 {\n font-size: 63px;\n }\n}\n.thumbnail {\n display: block;\n padding: 4px;\n margin-bottom: 20px;\n line-height: 1.42857143;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 4px;\n -webkit-transition: border 0.2s ease-in-out;\n -o-transition: border 0.2s ease-in-out;\n transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n margin-left: auto;\n margin-right: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n border-color: #337ab7;\n}\n.thumbnail .caption {\n padding: 9px;\n color: #333333;\n}\n.alert {\n padding: 15px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.alert h4 {\n margin-top: 0;\n color: inherit;\n}\n.alert .alert-link {\n font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n margin-bottom: 0;\n}\n.alert > p + p {\n margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n}\n.alert-success {\n background-color: #dff0d8;\n border-color: #d6e9c6;\n color: #3c763d;\n}\n.alert-success hr {\n border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n color: #2b542c;\n}\n.alert-info {\n background-color: #d9edf7;\n border-color: #bce8f1;\n color: #31708f;\n}\n.alert-info hr {\n border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n color: #245269;\n}\n.alert-warning {\n background-color: #fcf8e3;\n border-color: #faebcc;\n color: #8a6d3b;\n}\n.alert-warning hr {\n border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n color: #66512c;\n}\n.alert-danger {\n background-color: #f2dede;\n border-color: #ebccd1;\n color: #a94442;\n}\n.alert-danger hr {\n border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n.progress {\n overflow: hidden;\n height: 20px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: 12px;\n line-height: 20px;\n color: #ffffff;\n text-align: center;\n background-color: #337ab7;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n -webkit-transition: width 0.6s ease;\n -o-transition: width 0.6s ease;\n transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n -webkit-animation: progress-bar-stripes 2s linear infinite;\n -o-animation: progress-bar-stripes 2s linear infinite;\n animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n.media-middle {\n vertical-align: middle;\n}\n.media-bottom {\n vertical-align: bottom;\n}\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n.list-group {\n margin-bottom: 20px;\n padding-left: 0;\n}\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n margin-bottom: -1px;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n}\n.list-group-item:first-child {\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n}\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\na.list-group-item {\n color: #555555;\n}\na.list-group-item .list-group-item-heading {\n color: #333333;\n}\na.list-group-item:hover,\na.list-group-item:focus {\n text-decoration: none;\n color: #555555;\n background-color: #f5f5f5;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n background-color: #eeeeee;\n color: #777777;\n cursor: not-allowed;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n color: #777777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n z-index: 2;\n color: #ffffff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n color: #c7ddef;\n}\n.list-group-item-success {\n color: #3c763d;\n background-color: #dff0d8;\n}\na.list-group-item-success {\n color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-success:hover,\na.list-group-item-success:focus {\n color: #3c763d;\n background-color: #d0e9c6;\n}\na.list-group-item-success.active,\na.list-group-item-success.active:hover,\na.list-group-item-success.active:focus {\n color: #fff;\n background-color: #3c763d;\n border-color: #3c763d;\n}\n.list-group-item-info {\n color: #31708f;\n background-color: #d9edf7;\n}\na.list-group-item-info {\n color: #31708f;\n}\na.list-group-item-info .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-info:hover,\na.list-group-item-info:focus {\n color: #31708f;\n background-color: #c4e3f3;\n}\na.list-group-item-info.active,\na.list-group-item-info.active:hover,\na.list-group-item-info.active:focus {\n color: #fff;\n background-color: #31708f;\n border-color: #31708f;\n}\n.list-group-item-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n}\na.list-group-item-warning {\n color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-warning:hover,\na.list-group-item-warning:focus {\n color: #8a6d3b;\n background-color: #faf2cc;\n}\na.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus {\n color: #fff;\n background-color: #8a6d3b;\n border-color: #8a6d3b;\n}\n.list-group-item-danger {\n color: #a94442;\n background-color: #f2dede;\n}\na.list-group-item-danger {\n color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-danger:hover,\na.list-group-item-danger:focus {\n color: #a94442;\n background-color: #ebcccc;\n}\na.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus {\n color: #fff;\n background-color: #a94442;\n border-color: #a94442;\n}\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n.panel {\n margin-bottom: 20px;\n background-color: #ffffff;\n border: 1px solid transparent;\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n padding: 15px;\n}\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n color: inherit;\n}\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: 16px;\n color: inherit;\n}\n.panel-title > a {\n color: inherit;\n}\n.panel-footer {\n padding: 10px 15px;\n background-color: #f5f5f5;\n border-top: 1px solid #dddddd;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n border-top: 0;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n border-bottom: 0;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n border-top-width: 0;\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n padding-left: 15px;\n padding-right: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n border-bottom-left-radius: 3px;\n border-bottom-right-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n border-top: 1px solid #dddddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n border-bottom: 0;\n}\n.panel > .table-responsive {\n border: 0;\n margin-bottom: 0;\n}\n.panel-group {\n margin-bottom: 20px;\n}\n.panel-group .panel {\n margin-bottom: 0;\n border-radius: 4px;\n}\n.panel-group .panel + .panel {\n margin-top: 5px;\n}\n.panel-group .panel-heading {\n border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n border-top: 1px solid #dddddd;\n}\n.panel-group .panel-footer {\n border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n border-bottom: 1px solid #dddddd;\n}\n.panel-default {\n border-color: #dddddd;\n}\n.panel-default > .panel-heading {\n color: #333333;\n background-color: #f5f5f5;\n border-color: #dddddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #dddddd;\n}\n.panel-default > .panel-heading .badge {\n color: #f5f5f5;\n background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #dddddd;\n}\n.panel-primary {\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n color: #ffffff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n color: #337ab7;\n background-color: #ffffff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #337ab7;\n}\n.panel-success {\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n color: #dff0d8;\n background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #d6e9c6;\n}\n.panel-info {\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n color: #d9edf7;\n background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #bce8f1;\n}\n.panel-warning {\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n color: #fcf8e3;\n background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #faebcc;\n}\n.panel-danger {\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n color: #f2dede;\n background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n height: 100%;\n width: 100%;\n border: 0;\n}\n.embed-responsive.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n.embed-responsive.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border: 1px solid #e3e3e3;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n border-color: #ddd;\n border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n padding: 24px;\n border-radius: 6px;\n}\n.well-sm {\n padding: 9px;\n border-radius: 3px;\n}\n.close {\n float: right;\n font-size: 21px;\n font-weight: bold;\n line-height: 1;\n color: #000000;\n text-shadow: 0 1px 0 #ffffff;\n opacity: 0.2;\n filter: alpha(opacity=20);\n}\n.close:hover,\n.close:focus {\n color: #000000;\n text-decoration: none;\n cursor: pointer;\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\nbutton.close {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n}\n.modal-open {\n overflow: hidden;\n}\n.modal {\n display: none;\n overflow: hidden;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n -webkit-overflow-scrolling: touch;\n outline: 0;\n}\n.modal.fade .modal-dialog {\n -webkit-transform: translate(0, -25%);\n -ms-transform: translate(0, -25%);\n -o-transform: translate(0, -25%);\n transform: translate(0, -25%);\n -webkit-transition: -webkit-transform 0.3s ease-out;\n -moz-transition: -moz-transform 0.3s ease-out;\n -o-transition: -o-transform 0.3s ease-out;\n transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n -webkit-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n -o-transform: translate(0, 0);\n transform: translate(0, 0);\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n.modal-content {\n position: relative;\n background-color: #ffffff;\n border: 1px solid #999999;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n background-clip: padding-box;\n outline: 0;\n}\n.modal-backdrop {\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n background-color: #000000;\n}\n.modal-backdrop.fade {\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\n.modal-header {\n padding: 15px;\n border-bottom: 1px solid #e5e5e5;\n min-height: 16.42857143px;\n}\n.modal-header .close {\n margin-top: -2px;\n}\n.modal-title {\n margin: 0;\n line-height: 1.42857143;\n}\n.modal-body {\n position: relative;\n padding: 15px;\n}\n.modal-footer {\n padding: 15px;\n text-align: right;\n border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n margin-left: 5px;\n margin-bottom: 0;\n}\n.modal-footer .btn-group .btn + .btn {\n margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n margin-left: 0;\n}\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n@media (min-width: 768px) {\n .modal-dialog {\n width: 600px;\n margin: 30px auto;\n }\n .modal-content {\n -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n }\n .modal-sm {\n width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg {\n width: 900px;\n }\n}\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n visibility: visible;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 12px;\n font-weight: normal;\n line-height: 1.4;\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.tooltip.in {\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.tooltip.top {\n margin-top: -3px;\n padding: 5px 0;\n}\n.tooltip.right {\n margin-left: 3px;\n padding: 0 5px;\n}\n.tooltip.bottom {\n margin-top: 3px;\n padding: 5px 0;\n}\n.tooltip.left {\n margin-left: -3px;\n padding: 0 5px;\n}\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #ffffff;\n text-align: center;\n text-decoration: none;\n background-color: #000000;\n border-radius: 4px;\n}\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.top-left .tooltip-arrow {\n bottom: 0;\n right: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.top-right .tooltip-arrow {\n bottom: 0;\n left: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -5px;\n border-width: 5px 5px 5px 0;\n border-right-color: #000000;\n}\n.tooltip.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -5px;\n border-width: 5px 0 5px 5px;\n border-left-color: #000000;\n}\n.tooltip.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n top: 0;\n right: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n top: 0;\n left: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: none;\n max-width: 276px;\n padding: 1px;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n font-weight: normal;\n line-height: 1.42857143;\n text-align: left;\n background-color: #ffffff;\n background-clip: padding-box;\n border: 1px solid #cccccc;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n white-space: normal;\n}\n.popover.top {\n margin-top: -10px;\n}\n.popover.right {\n margin-left: 10px;\n}\n.popover.bottom {\n margin-top: 10px;\n}\n.popover.left {\n margin-left: -10px;\n}\n.popover-title {\n margin: 0;\n padding: 8px 14px;\n font-size: 14px;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-radius: 5px 5px 0 0;\n}\n.popover-content {\n padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover > .arrow {\n border-width: 11px;\n}\n.popover > .arrow:after {\n border-width: 10px;\n content: \"\";\n}\n.popover.top > .arrow {\n left: 50%;\n margin-left: -11px;\n border-bottom-width: 0;\n border-top-color: #999999;\n border-top-color: rgba(0, 0, 0, 0.25);\n bottom: -11px;\n}\n.popover.top > .arrow:after {\n content: \" \";\n bottom: 1px;\n margin-left: -10px;\n border-bottom-width: 0;\n border-top-color: #ffffff;\n}\n.popover.right > .arrow {\n top: 50%;\n left: -11px;\n margin-top: -11px;\n border-left-width: 0;\n border-right-color: #999999;\n border-right-color: rgba(0, 0, 0, 0.25);\n}\n.popover.right > .arrow:after {\n content: \" \";\n left: 1px;\n bottom: -10px;\n border-left-width: 0;\n border-right-color: #ffffff;\n}\n.popover.bottom > .arrow {\n left: 50%;\n margin-left: -11px;\n border-top-width: 0;\n border-bottom-color: #999999;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n top: -11px;\n}\n.popover.bottom > .arrow:after {\n content: \" \";\n top: 1px;\n margin-left: -10px;\n border-top-width: 0;\n border-bottom-color: #ffffff;\n}\n.popover.left > .arrow {\n top: 50%;\n right: -11px;\n margin-top: -11px;\n border-right-width: 0;\n border-left-color: #999999;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n content: \" \";\n right: 1px;\n border-right-width: 0;\n border-left-color: #ffffff;\n bottom: -10px;\n}\n.carousel {\n position: relative;\n}\n.carousel-inner {\n position: relative;\n overflow: hidden;\n width: 100%;\n}\n.carousel-inner > .item {\n display: none;\n position: relative;\n -webkit-transition: 0.6s ease-in-out left;\n -o-transition: 0.6s ease-in-out left;\n transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n .carousel-inner > .item {\n transition: transform 0.6s ease-in-out;\n backface-visibility: hidden;\n perspective: 1000;\n }\n .carousel-inner > .item.next,\n .carousel-inner > .item.active.right {\n transform: translate3d(100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.prev,\n .carousel-inner > .item.active.left {\n transform: translate3d(-100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.next.left,\n .carousel-inner > .item.prev.right,\n .carousel-inner > .item.active {\n transform: translate3d(0, 0, 0);\n left: 0;\n }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n display: block;\n}\n.carousel-inner > .active {\n left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n}\n.carousel-inner > .next {\n left: 100%;\n}\n.carousel-inner > .prev {\n left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n left: 0;\n}\n.carousel-inner > .active.left {\n left: -100%;\n}\n.carousel-inner > .active.right {\n left: 100%;\n}\n.carousel-control {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n width: 15%;\n opacity: 0.5;\n filter: alpha(opacity=50);\n font-size: 20px;\n color: #ffffff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-control.left {\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n left: auto;\n right: 0;\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n outline: 0;\n color: #ffffff;\n text-decoration: none;\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n z-index: 5;\n display: inline-block;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n width: 20px;\n height: 20px;\n margin-top: -10px;\n font-family: serif;\n}\n.carousel-control .icon-prev:before {\n content: '\\2039';\n}\n.carousel-control .icon-next:before {\n content: '\\203a';\n}\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n margin-left: -30%;\n padding-left: 0;\n list-style: none;\n text-align: center;\n}\n.carousel-indicators li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n border: 1px solid #ffffff;\n border-radius: 10px;\n cursor: pointer;\n background-color: #000 \\9;\n background-color: rgba(0, 0, 0, 0);\n}\n.carousel-indicators .active {\n margin: 0;\n width: 12px;\n height: 12px;\n background-color: #ffffff;\n}\n.carousel-caption {\n position: absolute;\n left: 15%;\n right: 15%;\n bottom: 20px;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #ffffff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-prev,\n .carousel-control .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -15px;\n font-size: 30px;\n }\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .icon-prev {\n margin-left: -15px;\n }\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-next {\n margin-right: -15px;\n }\n .carousel-caption {\n left: 20%;\n right: 20%;\n padding-bottom: 30px;\n }\n .carousel-indicators {\n bottom: 20px;\n }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-footer:before,\n.modal-footer:after {\n content: \" \";\n display: table;\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-footer:after {\n clear: both;\n}\n.center-block {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n.hidden {\n display: none !important;\n visibility: hidden !important;\n}\n.affix {\n position: fixed;\n}\n@-ms-viewport {\n width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n@media (max-width: 767px) {\n .visible-xs {\n display: block !important;\n }\n table.visible-xs {\n display: table;\n }\n tr.visible-xs {\n display: table-row !important;\n }\n th.visible-xs,\n td.visible-xs {\n display: table-cell !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-block {\n display: block !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline {\n display: inline !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm {\n display: block !important;\n }\n table.visible-sm {\n display: table;\n }\n tr.visible-sm {\n display: table-row !important;\n }\n th.visible-sm,\n td.visible-sm {\n display: table-cell !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-block {\n display: block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline {\n display: inline !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md {\n display: block !important;\n }\n table.visible-md {\n display: table;\n }\n tr.visible-md {\n display: table-row !important;\n }\n th.visible-md,\n td.visible-md {\n display: table-cell !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-block {\n display: block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline {\n display: inline !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg {\n display: block !important;\n }\n table.visible-lg {\n display: table;\n }\n tr.visible-lg {\n display: table-row !important;\n }\n th.visible-lg,\n td.visible-lg {\n display: table-cell !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-block {\n display: block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline {\n display: inline !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline-block {\n display: inline-block !important;\n }\n}\n@media (max-width: 767px) {\n .hidden-xs {\n display: none !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .hidden-sm {\n display: none !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .hidden-md {\n display: none !important;\n }\n}\n@media (min-width: 1200px) {\n .hidden-lg {\n display: none !important;\n }\n}\n.visible-print {\n display: none !important;\n}\n@media print {\n .visible-print {\n display: block !important;\n }\n table.visible-print {\n display: table;\n }\n tr.visible-print {\n display: table-row !important;\n }\n th.visible-print,\n td.visible-print {\n display: table-cell !important;\n }\n}\n.visible-print-block {\n display: none !important;\n}\n@media print {\n .visible-print-block {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n}\n@media print {\n .visible-print-inline {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n}\n@media print {\n .visible-print-inline-block {\n display: inline-block !important;\n }\n}\n@media print {\n .hidden-print {\n display: none !important;\n }\n}\n/*# sourceMappingURL=bootstrap.css.map */","/*! normalize.css v3.0.2 | MIT License | git.io/normalize */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS text size adjust after orientation change, without disabling\n// user zoom.\n//\n\nhtml {\n font-family: sans-serif; // 1\n -ms-text-size-adjust: 100%; // 2\n -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined for any HTML5 element in IE 8/9.\n// Correct `block` display not defined for `details` or `summary` in IE 10/11\n// and Firefox.\n// Correct `block` display not defined for `main` in IE 11.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block; // 1\n vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9/10.\n// Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n background-color: transparent;\n}\n\n//\n// Improve readability when focused and also mouse hovered in all browsers.\n//\n\na:active,\na:hover {\n outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n//\n\nabbr[title] {\n border-bottom: 1px dotted;\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n//\n\nb,\nstrong {\n font-weight: bold;\n}\n\n//\n// Address styling not present in Safari and Chrome.\n//\n\ndfn {\n font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari, and Chrome.\n//\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n background: #ff0;\n color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsup {\n top: -0.5em;\n}\n\nsub {\n bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9/10.\n//\n\nimg {\n border: 0;\n}\n\n//\n// Correct overflow not hidden in IE 9/10/11.\n//\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari.\n//\n\nfigure {\n margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n// Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit; // 1\n font: inherit; // 2\n margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10/11.\n//\n\nbutton {\n overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n// and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n// `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button; // 2\n cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box; // 1\n padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari and Chrome\n// (include `-moz` to future-proof).\n//\n\ninput[type=\"search\"] {\n -webkit-appearance: textfield; // 1\n -moz-box-sizing: content-box;\n -webkit-box-sizing: content-box; // 2\n box-sizing: content-box;\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9/10/11.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n border: 0; // 1\n padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9/10/11.\n//\n\ntextarea {\n overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\n\ntd,\nth {\n padding: 0;\n}\n","/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n\n// ==========================================================================\n// Print styles.\n// Inlined to avoid the additional HTTP request: h5bp.com/r\n// ==========================================================================\n\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important; // Black prints faster: h5bp.com/s\n box-shadow: none !important;\n text-shadow: none !important;\n }\n\n a,\n a:visited {\n text-decoration: underline;\n }\n\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n\n // Don't show links that are fragment identifiers,\n // or use the `javascript:` pseudo protocol\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n\n thead {\n display: table-header-group; // h5bp.com/t\n }\n\n tr,\n img {\n page-break-inside: avoid;\n }\n\n img {\n max-width: 100% !important;\n }\n\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n\n h2,\n h3 {\n page-break-after: avoid;\n }\n\n // Bootstrap specific changes start\n //\n // Chrome (OSX) fix for https://github.com/twbs/bootstrap/issues/11245\n // Once fixed, we can just straight up remove this.\n select {\n background: #fff !important;\n }\n\n // Bootstrap components\n .navbar {\n display: none;\n }\n .btn,\n .dropup > .btn {\n > .caret {\n border-top-color: #000 !important;\n }\n }\n .label {\n border: 1px solid #000;\n }\n\n .table {\n border-collapse: collapse !important;\n\n td,\n th {\n background-color: #fff !important;\n }\n }\n .table-bordered {\n th,\n td {\n border: 1px solid #ddd !important;\n }\n }\n\n // Bootstrap specific changes end\n}\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// <a href=\"#\"><span class=\"glyphicon glyphicon-star\"></span> Star</a>\n\n// Import the fonts\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('@{icon-font-path}@{icon-font-name}.eot');\n src: url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype'),\n url('@{icon-font-path}@{icon-font-name}.woff') format('woff'),\n url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype'),\n url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg');\n}\n\n// Catchall baseclass\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk { &:before { content: \"\\2a\"; } }\n.glyphicon-plus { &:before { content: \"\\2b\"; } }\n.glyphicon-euro,\n.glyphicon-eur { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil { &:before { content: \"\\270f\"; } }\n.glyphicon-glass { &:before { content: \"\\e001\"; } }\n.glyphicon-music { &:before { content: \"\\e002\"; } }\n.glyphicon-search { &:before { content: \"\\e003\"; } }\n.glyphicon-heart { &:before { content: \"\\e005\"; } }\n.glyphicon-star { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty { &:before { content: \"\\e007\"; } }\n.glyphicon-user { &:before { content: \"\\e008\"; } }\n.glyphicon-film { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large { &:before { content: \"\\e010\"; } }\n.glyphicon-th { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list { &:before { content: \"\\e012\"; } }\n.glyphicon-ok { &:before { content: \"\\e013\"; } }\n.glyphicon-remove { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out { &:before { content: \"\\e016\"; } }\n.glyphicon-off { &:before { content: \"\\e017\"; } }\n.glyphicon-signal { &:before { content: \"\\e018\"; } }\n.glyphicon-cog { &:before { content: \"\\e019\"; } }\n.glyphicon-trash { &:before { content: \"\\e020\"; } }\n.glyphicon-home { &:before { content: \"\\e021\"; } }\n.glyphicon-file { &:before { content: \"\\e022\"; } }\n.glyphicon-time { &:before { content: \"\\e023\"; } }\n.glyphicon-road { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt { &:before { content: \"\\e025\"; } }\n.glyphicon-download { &:before { content: \"\\e026\"; } }\n.glyphicon-upload { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt { &:before { content: \"\\e032\"; } }\n.glyphicon-lock { &:before { content: \"\\e033\"; } }\n.glyphicon-flag { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode { &:before { content: \"\\e040\"; } }\n.glyphicon-tag { &:before { content: \"\\e041\"; } }\n.glyphicon-tags { &:before { content: \"\\e042\"; } }\n.glyphicon-book { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark { &:before { content: \"\\e044\"; } }\n.glyphicon-print { &:before { content: \"\\e045\"; } }\n.glyphicon-camera { &:before { content: \"\\e046\"; } }\n.glyphicon-font { &:before { content: \"\\e047\"; } }\n.glyphicon-bold { &:before { content: \"\\e048\"; } }\n.glyphicon-italic { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify { &:before { content: \"\\e055\"; } }\n.glyphicon-list { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video { &:before { content: \"\\e059\"; } }\n.glyphicon-picture { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust { &:before { content: \"\\e063\"; } }\n.glyphicon-tint { &:before { content: \"\\e064\"; } }\n.glyphicon-edit { &:before { content: \"\\e065\"; } }\n.glyphicon-share { &:before { content: \"\\e066\"; } }\n.glyphicon-check { &:before { content: \"\\e067\"; } }\n.glyphicon-move { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward { &:before { content: \"\\e070\"; } }\n.glyphicon-backward { &:before { content: \"\\e071\"; } }\n.glyphicon-play { &:before { content: \"\\e072\"; } }\n.glyphicon-pause { &:before { content: \"\\e073\"; } }\n.glyphicon-stop { &:before { content: \"\\e074\"; } }\n.glyphicon-forward { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward { &:before { content: \"\\e077\"; } }\n.glyphicon-eject { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign { &:before { content: \"\\e101\"; } }\n.glyphicon-gift { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf { &:before { content: \"\\e103\"; } }\n.glyphicon-fire { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign { &:before { content: \"\\e107\"; } }\n.glyphicon-plane { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar { &:before { content: \"\\e109\"; } }\n.glyphicon-random { &:before { content: \"\\e110\"; } }\n.glyphicon-comment { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn { &:before { content: \"\\e122\"; } }\n.glyphicon-bell { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down { &:before { content: \"\\e134\"; } }\n.glyphicon-globe { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks { &:before { content: \"\\e137\"; } }\n.glyphicon-filter { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty { &:before { content: \"\\e143\"; } }\n.glyphicon-link { &:before { content: \"\\e144\"; } }\n.glyphicon-phone { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin { &:before { content: \"\\e146\"; } }\n.glyphicon-usd { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp { &:before { content: \"\\e149\"; } }\n.glyphicon-sort { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked { &:before { content: \"\\e157\"; } }\n.glyphicon-expand { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in { &:before { content: \"\\e161\"; } }\n.glyphicon-flash { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window { &:before { content: \"\\e164\"; } }\n.glyphicon-record { &:before { content: \"\\e165\"; } }\n.glyphicon-save { &:before { content: \"\\e166\"; } }\n.glyphicon-open { &:before { content: \"\\e167\"; } }\n.glyphicon-saved { &:before { content: \"\\e168\"; } }\n.glyphicon-import { &:before { content: \"\\e169\"; } }\n.glyphicon-export { &:before { content: \"\\e170\"; } }\n.glyphicon-send { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery { &:before { content: \"\\e179\"; } }\n.glyphicon-header { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt { &:before { content: \"\\e183\"; } }\n.glyphicon-tower { &:before { content: \"\\e184\"; } }\n.glyphicon-stats { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1 { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1 { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1 { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous { &:before { content: \"\\e200\"; } }\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// http://getbootstrap.com/getting-started/#third-box-sizing\n* {\n .box-sizing(border-box);\n}\n*:before,\n*:after {\n .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n font-family: @font-family-base;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @text-color;\n background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\n\n// Links\n\na {\n color: @link-color;\n text-decoration: none;\n\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n }\n\n &:focus {\n .tab-focus();\n }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n margin: 0;\n}\n\n\n// Images\n\nimg {\n vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n padding: @thumbnail-padding;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(all .2s ease-in-out);\n\n // Keep them at most 100% wide\n .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n margin-top: @line-height-computed;\n margin-bottom: @line-height-computed;\n border: 0;\n border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: http://a11yproject.com/posts/how-to-hide-content/\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0,0,0,0);\n border: 0;\n}\n\n// Use in conjunction with .sr-only to only display content when it's focused.\n// Useful for \"Skip to main content\" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n// Credit: HTML5 Boilerplate\n\n.sr-only-focusable {\n &:active,\n &:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n }\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // See https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// WebKit-style focus\n\n.tab-focus() {\n // Default\n outline: thin dotted;\n // WebKit\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n","// Image Mixins\n// - Responsive image\n// - Retina image\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// Retina image\n//\n// Short retina mixin for setting background-image and -size. Note that the\n// spelling of `min--moz-device-pixel-ratio` is intentional.\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n font-family: @headings-font-family;\n font-weight: @headings-font-weight;\n line-height: @headings-line-height;\n color: @headings-color;\n\n small,\n .small {\n font-weight: normal;\n line-height: 1;\n color: @headings-small-color;\n }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n margin-top: @line-height-computed;\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 65%;\n }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n margin-top: (@line-height-computed / 2);\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 75%;\n }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n margin-bottom: @line-height-computed;\n font-size: floor((@font-size-base * 1.15));\n font-weight: 300;\n line-height: 1.4;\n\n @media (min-width: @screen-sm-min) {\n font-size: (@font-size-base * 1.5);\n }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: (12px small font / 14px base font) * 100% = about 85%\nsmall,\n.small {\n font-size: floor((100% * @font-size-small / @font-size-base));\n}\n\nmark,\n.mark {\n background-color: @state-warning-bg;\n padding: .2em;\n}\n\n// Alignment\n.text-left { text-align: left; }\n.text-right { text-align: right; }\n.text-center { text-align: center; }\n.text-justify { text-align: justify; }\n.text-nowrap { white-space: nowrap; }\n\n// Transformation\n.text-lowercase { text-transform: lowercase; }\n.text-uppercase { text-transform: uppercase; }\n.text-capitalize { text-transform: capitalize; }\n\n// Contextual colors\n.text-muted {\n color: @text-muted;\n}\n.text-primary {\n .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n // Given the contrast here, this is the only class to have its color inverted\n // automatically.\n color: #fff;\n .bg-variant(@brand-primary);\n}\n.bg-success {\n .bg-variant(@state-success-bg);\n}\n.bg-info {\n .bg-variant(@state-info-bg);\n}\n.bg-warning {\n .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n padding-bottom: ((@line-height-computed / 2) - 1);\n margin: (@line-height-computed * 2) 0 @line-height-computed;\n border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// -------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n margin-top: 0;\n margin-bottom: (@line-height-computed / 2);\n ul,\n ol {\n margin-bottom: 0;\n }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n .list-unstyled();\n margin-left: -5px;\n\n > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n }\n}\n\n// Description Lists\ndl {\n margin-top: 0; // Remove browser default\n margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n line-height: @line-height-base;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n.dl-horizontal {\n dd {\n &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n }\n\n @media (min-width: @grid-float-breakpoint) {\n dt {\n float: left;\n width: (@dl-horizontal-offset - 20);\n clear: left;\n text-align: right;\n .text-overflow();\n }\n dd {\n margin-left: @dl-horizontal-offset;\n }\n }\n}\n\n\n// Misc\n// -------------------------\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\n\n// Blockquotes\nblockquote {\n padding: (@line-height-computed / 2) @line-height-computed;\n margin: 0 0 @line-height-computed;\n font-size: @blockquote-font-size;\n border-left: 5px solid @blockquote-border-color;\n\n p,\n ul,\n ol {\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // Note: Deprecated small and .small as of v3.1.0\n // Context: https://github.com/twbs/bootstrap/issues/11660\n footer,\n small,\n .small {\n display: block;\n font-size: 80%; // back to default font-size\n line-height: @line-height-base;\n color: @blockquote-small-color;\n\n &:before {\n content: '\\2014 \\00A0'; // em dash, nbsp\n }\n }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid @blockquote-border-color;\n border-left: 0;\n text-align: right;\n\n // Account for citation\n footer,\n small,\n .small {\n &:before { content: ''; }\n &:after {\n content: '\\00A0 \\2014'; // nbsp, em dash\n }\n }\n}\n\n// Addresses\naddress {\n margin-bottom: @line-height-computed;\n font-style: normal;\n line-height: @line-height-base;\n}\n","// Typography\n\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover {\n color: darken(@color, 10%);\n }\n}\n","// Contextual backgrounds\n\n.bg-variant(@color) {\n background-color: @color;\n a&:hover {\n background-color: darken(@color, 10%);\n }\n}\n","// Text overflow\n// Requires inline-block or block for proper styling\n\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: @code-color;\n background-color: @code-bg;\n border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: @kbd-color;\n background-color: @kbd-bg;\n border-radius: @border-radius-small;\n box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n\n kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n }\n}\n\n// Blocks of code\npre {\n display: block;\n padding: ((@line-height-computed - 1) / 2);\n margin: 0 0 (@line-height-computed / 2);\n font-size: (@font-size-base - 1); // 14px to 13px\n line-height: @line-height-base;\n word-break: break-all;\n word-wrap: break-word;\n color: @pre-color;\n background-color: @pre-bg;\n border: 1px solid @pre-border-color;\n border-radius: @border-radius-base;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n max-height: @pre-scrollable-max-height;\n overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n .container-fixed();\n\n @media (min-width: @screen-sm-min) {\n width: @container-sm;\n }\n @media (min-width: @screen-md-min) {\n width: @container-md;\n }\n @media (min-width: @screen-lg-min) {\n width: @container-lg;\n }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n .make-grid(lg);\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n// Centered container element\n.container-fixed(@gutter: @grid-gutter-width) {\n margin-right: auto;\n margin-left: auto;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-left: (@gutter / -2);\n margin-right: (@gutter / -2);\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n margin-left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-push(@columns) {\n left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-pull(@columns) {\n right: percentage((@columns / @grid-columns));\n}\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n","// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {\n .col-@{class}-push-0 {\n left: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {\n .col-@{class}-pull-0 {\n right: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n background-color: @table-bg;\n}\ncaption {\n padding-top: @table-cell-padding;\n padding-bottom: @table-cell-padding;\n color: @text-muted;\n text-align: left;\n}\nth {\n text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: @line-height-computed;\n // Cells\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-cell-padding;\n line-height: @line-height-base;\n vertical-align: top;\n border-top: 1px solid @table-border-color;\n }\n }\n }\n // Bottom align for column headings\n > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid @table-border-color;\n }\n // Remove top border from thead by default\n > caption + thead,\n > colgroup + thead,\n > thead:first-child {\n > tr:first-child {\n > th,\n > td {\n border-top: 0;\n }\n }\n }\n // Account for multiple tbody instances\n > tbody + tbody {\n border-top: 2px solid @table-border-color;\n }\n\n // Nesting\n .table {\n background-color: @body-bg;\n }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-condensed-cell-padding;\n }\n }\n }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n border: 1px solid @table-border-color;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n border: 1px solid @table-border-color;\n }\n }\n }\n > thead > tr {\n > th,\n > td {\n border-bottom-width: 2px;\n }\n }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n > tbody > tr:nth-child(odd) {\n background-color: @table-bg-accent;\n }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n > tbody > tr:hover {\n background-color: @table-bg-hover;\n }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-column;\n}\ntable {\n td,\n th {\n &[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-cell;\n }\n }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)\n\n @media screen and (max-width: @screen-xs-max) {\n width: 100%;\n margin-bottom: (@line-height-computed * 0.75);\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid @table-border-color;\n\n // Tighten up spacing\n > .table {\n margin-bottom: 0;\n\n // Ensure the content doesn't wrap\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n white-space: nowrap;\n }\n }\n }\n }\n\n // Special overrides for the bordered tables\n > .table-bordered {\n border: 0;\n\n // Nuke the appropriate borders so that the parent can handle them\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n\n // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n // chances are there will be only one `tr` in a `thead` and that would\n // remove the border altogether.\n > tbody,\n > tfoot {\n > tr:last-child {\n > th,\n > td {\n border-bottom: 0;\n }\n }\n }\n\n }\n }\n}\n","// Tables\n\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &:hover > .@{state},\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n // Chrome and Firefox set a `min-width: min-content;` on fieldsets,\n // so we reset that to ensure it behaves more like a standard block element.\n // See https://github.com/twbs/bootstrap/issues/12359.\n min-width: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: @line-height-computed;\n font-size: (@font-size-base * 1.5);\n line-height: inherit;\n color: @legend-color;\n border: 0;\n border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n display: inline-block;\n max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)\n margin-bottom: 5px;\n font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9; // IE8-9\n line-height: normal;\n}\n\n// Set the height of file controls to match text inputs\ninput[type=\"file\"] {\n display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n .tab-focus();\n}\n\n// Adjust output element\noutput {\n display: block;\n padding-top: (@padding-base-vertical + 1);\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n display: block;\n width: 100%;\n height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n background-color: @input-bg;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid @input-border;\n border-radius: @input-border-radius;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n // Customize the `:focus` state to imitate native WebKit styles.\n .form-control-focus();\n\n // Placeholder\n .placeholder();\n\n // Disabled and read-only inputs\n //\n // HTML5 says that controls under a fieldset > legend:first-child won't be\n // disabled if the fieldset is disabled. Due to implementation difficulty, we\n // don't honor that edge case; we style them as disabled anyway.\n &[disabled],\n &[readonly],\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n background-color: @input-bg-disabled;\n opacity: 1; // iOS fix for unreadable disabled content\n }\n\n // Reset height for `textarea`s\n textarea& {\n height: auto;\n }\n}\n\n\n// Search inputs in iOS\n//\n// This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n\n\n// Special styles for iOS temporal inputs\n//\n// In Mobile Safari, setting `display: block` on temporal inputs causes the\n// text within the input to become vertically misaligned. As a workaround, we\n// set a pixel line-height that matches the given height of the input, but only\n// for Safari.\n\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"],\n input[type=\"time\"],\n input[type=\"datetime-local\"],\n input[type=\"month\"] {\n line-height: @input-height-base;\n }\n input[type=\"date\"].input-sm,\n input[type=\"time\"].input-sm,\n input[type=\"datetime-local\"].input-sm,\n input[type=\"month\"].input-sm {\n line-height: @input-height-small;\n }\n input[type=\"date\"].input-lg,\n input[type=\"time\"].input-lg,\n input[type=\"datetime-local\"].input-lg,\n input[type=\"month\"].input-lg {\n line-height: @input-height-large;\n }\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n margin-bottom: 15px;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n\n label {\n min-height: @line-height-computed; // Ensure the input doesn't jump when there is no text\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n cursor: pointer;\n }\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-left: -20px;\n margin-top: 4px \\9;\n}\n\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px; // space out consecutive inline controls\n}\n\n// Apply same disabled cursor tweak as for inputs\n// Some special care is needed because <label>s don't inherit their parent's `cursor`.\n//\n// Note: Neither radios nor checkboxes can be readonly.\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n &[disabled],\n &.disabled,\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n}\n// These classes are used directly on <label>s\n.radio-inline,\n.checkbox-inline {\n &.disabled,\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n}\n// These classes are used on elements with <label> descendants\n.radio,\n.checkbox {\n &.disabled,\n fieldset[disabled] & {\n label {\n cursor: @cursor-disabled;\n }\n }\n}\n\n\n// Static form control text\n//\n// Apply class to a `p` element to make any string of text align with labels in\n// a horizontal form layout.\n\n.form-control-static {\n // Size it appropriately next to real form controls\n padding-top: (@padding-base-vertical + 1);\n padding-bottom: (@padding-base-vertical + 1);\n // Remove default margin from `p`\n margin-bottom: 0;\n\n &.input-lg,\n &.input-sm {\n padding-left: 0;\n padding-right: 0;\n }\n}\n\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n\n.input-sm,\n.form-group-sm .form-control {\n .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @input-border-radius-small);\n}\n\n.input-lg,\n.form-group-lg .form-control {\n .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @input-border-radius-large);\n}\n\n\n// Form control feedback states\n//\n// Apply contextual and semantic states to individual form controls.\n\n.has-feedback {\n // Enable absolute positioning\n position: relative;\n\n // Ensure icons don't overlap text\n .form-control {\n padding-right: (@input-height-base * 1.25);\n }\n}\n// Feedback icon (requires .glyphicon classes)\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2; // Ensure icon is above input groups\n display: block;\n width: @input-height-base;\n height: @input-height-base;\n line-height: @input-height-base;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback {\n width: @input-height-large;\n height: @input-height-large;\n line-height: @input-height-large;\n}\n.input-sm + .form-control-feedback {\n width: @input-height-small;\n height: @input-height-small;\n line-height: @input-height-small;\n}\n\n// Feedback states\n.has-success {\n .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);\n}\n.has-warning {\n .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);\n}\n.has-error {\n .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);\n}\n\n// Reposition feedback icon if input has visible label above\n.has-feedback label {\n\n & ~ .form-control-feedback {\n top: (@line-height-computed + 5); // Height of the `label` and its margin\n }\n &.sr-only ~ .form-control-feedback {\n top: 0;\n }\n}\n\n\n// Help text\n//\n// Apply to any element you wish to create light text for placement immediately\n// below a form control. Use for general help, formatting, or instructional text.\n\n.help-block {\n display: block; // account for any element using help-block\n margin-top: 5px;\n margin-bottom: 10px;\n color: lighten(@text-color, 25%); // lighten the text some for contrast\n}\n\n\n// Inline forms\n//\n// Make forms appear inline(-block) by adding the `.form-inline` class. Inline\n// forms begin stacked on extra small (mobile) devices and then go inline when\n// viewports reach <768px.\n//\n// Requires wrapping inputs and labels with `.form-group` for proper display of\n// default HTML form controls and our custom form controls (e.g., input groups).\n//\n// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.\n\n.form-inline {\n\n // Kick in the inline\n @media (min-width: @screen-sm-min) {\n // Inline-block all the things for \"inline\"\n .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // In navbar-form, allow folks to *not* use `.form-group`\n .form-control {\n display: inline-block;\n width: auto; // Prevent labels from stacking above inputs in `.form-group`\n vertical-align: middle;\n }\n\n // Make static controls behave like regular ones\n .form-control-static {\n display: inline-block;\n }\n\n .input-group {\n display: inline-table;\n vertical-align: middle;\n\n .input-group-addon,\n .input-group-btn,\n .form-control {\n width: auto;\n }\n }\n\n // Input groups need that 100% width though\n .input-group > .form-control {\n width: 100%;\n }\n\n .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // Remove default margin on radios/checkboxes that were used for stacking, and\n // then undo the floating of radios and checkboxes to match (which also avoids\n // a bug in WebKit: https://github.com/twbs/bootstrap/issues/1969).\n .radio,\n .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n\n label {\n padding-left: 0;\n }\n }\n .radio input[type=\"radio\"],\n .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n\n // Re-override the feedback icon.\n .has-feedback .form-control-feedback {\n top: 0;\n }\n }\n}\n\n\n// Horizontal forms\n//\n// Horizontal forms are built on grid classes and allow you to create forms with\n// labels on the left and inputs on the right.\n\n.form-horizontal {\n\n // Consistent vertical alignment of radios and checkboxes\n //\n // Labels also get some reset styles, but that is scoped to a media query below.\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline {\n margin-top: 0;\n margin-bottom: 0;\n padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n }\n // Account for padding we're adding to ensure the alignment and of help text\n // and other content below items\n .radio,\n .checkbox {\n min-height: (@line-height-computed + (@padding-base-vertical + 1));\n }\n\n // Make form groups behave like rows\n .form-group {\n .make-row();\n }\n\n // Reset spacing and right align labels, but scope to media queries so that\n // labels on narrow viewports stack the same as a default form example.\n @media (min-width: @screen-sm-min) {\n .control-label {\n text-align: right;\n margin-bottom: 0;\n padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n }\n }\n\n // Validation states\n //\n // Reposition the icon because it's now within a grid column and columns have\n // `position: relative;` on them. Also accounts for the grid gutter padding.\n .has-feedback .form-control-feedback {\n right: (@grid-gutter-width / 2);\n }\n\n // Form group sizes\n //\n // Quick utility class for applying `.input-lg` and `.input-sm` styles to the\n // inputs and labels within a `.form-group`.\n .form-group-lg {\n @media (min-width: @screen-sm-min) {\n .control-label {\n padding-top: ((@padding-large-vertical * @line-height-large) + 1);\n }\n }\n }\n .form-group-sm {\n @media (min-width: @screen-sm-min) {\n .control-label {\n padding-top: (@padding-small-vertical + 1);\n }\n }\n }\n}\n","// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n // Color the label and help text\n .help-block,\n .control-label,\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline,\n &.radio label,\n &.checkbox label,\n &.radio-inline label,\n &.checkbox-inline label {\n color: @text-color;\n }\n // Set the border and box shadow on specific inputs to match\n .form-control {\n border-color: @border-color;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n &:focus {\n border-color: darken(@border-color, 10%);\n @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n .box-shadow(@shadow);\n }\n }\n // Set validation states also for addons\n .input-group-addon {\n color: @text-color;\n border-color: @border-color;\n background-color: @background-color;\n }\n // Optional feedback icon\n .form-control-feedback {\n color: @text-color;\n }\n}\n\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-border-focus` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n.form-control-focus(@color: @input-border-focus) {\n @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n &:focus {\n border-color: @color;\n outline: 0;\n .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. `<select>`\n// element gets special love because it's special, and that's a fact!\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n height: @input-height;\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n\n select& {\n height: @input-height;\n line-height: @input-height;\n }\n\n textarea&,\n select[multiple]& {\n height: auto;\n }\n}\n","//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n display: inline-block;\n margin-bottom: 0; // For input.btn\n font-weight: @btn-font-weight;\n text-align: center;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n white-space: nowrap;\n .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @border-radius-base);\n .user-select(none);\n\n &,\n &:active,\n &.active {\n &:focus,\n &.focus {\n .tab-focus();\n }\n }\n\n &:hover,\n &:focus,\n &.focus {\n color: @btn-default-color;\n text-decoration: none;\n }\n\n &:active,\n &.active {\n outline: 0;\n background-image: none;\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n pointer-events: none; // Future-proof disabling of clicks\n .opacity(.65);\n .box-shadow(none);\n }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n color: @link-color;\n font-weight: normal;\n border-radius: 0;\n\n &,\n &:active,\n &.active,\n &[disabled],\n fieldset[disabled] & {\n background-color: transparent;\n .box-shadow(none);\n }\n &,\n &:hover,\n &:focus,\n &:active {\n border-color: transparent;\n }\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: underline;\n background-color: transparent;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @btn-link-disabled-color;\n text-decoration: none;\n }\n }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n // line-height: ensure even-numbered height of button next to large input\n .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n.btn-sm {\n // line-height: ensure proper height of button next to small input\n .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n.btn-xs {\n .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n display: block;\n width: 100%;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n &.btn-block {\n width: 100%;\n }\n}\n","// Button variants\n//\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n\n.button-variant(@color; @background; @border) {\n color: @color;\n background-color: @background;\n border-color: @border;\n\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active,\n .open > .dropdown-toggle& {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 12%);\n }\n &:active,\n &.active,\n .open > .dropdown-toggle& {\n background-image: none;\n }\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: @background;\n border-color: @border;\n }\n }\n\n .badge {\n color: @background;\n background-color: @color;\n }\n}\n\n// Button sizes\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n}\n","// Opacity\n\n.opacity(@opacity) {\n opacity: @opacity;\n // IE8 filter\n @opacity-ie: (@opacity * 100);\n filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n","//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.\n\n.fade {\n opacity: 0;\n .transition(opacity .15s linear);\n &.in {\n opacity: 1;\n }\n}\n\n.collapse {\n display: none;\n visibility: hidden;\n\n &.in { display: block; visibility: visible; }\n tr&.in { display: table-row; }\n tbody&.in { display: table-row-group; }\n}\n\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n .transition-property(~\"height, visibility\");\n .transition-duration(.35s);\n .transition-timing-function(ease);\n}\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: @caret-width-base solid;\n border-right: @caret-width-base solid transparent;\n border-left: @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropdown {\n position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: @zindex-dropdown;\n display: none; // none by default, but block on \"open\" of the menu\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0; // override default ul\n list-style: none;\n font-size: @font-size-base;\n text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)\n background-color: @dropdown-bg;\n border: 1px solid @dropdown-fallback-border; // IE8 fallback\n border: 1px solid @dropdown-border;\n border-radius: @border-radius-base;\n .box-shadow(0 6px 12px rgba(0,0,0,.175));\n background-clip: padding-box;\n\n // Aligns the dropdown menu to right\n //\n // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n &.pull-right {\n right: 0;\n left: auto;\n }\n\n // Dividers (basically an hr) within the dropdown\n .divider {\n .nav-divider(@dropdown-divider-bg);\n }\n\n // Links within the dropdown menu\n > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: @line-height-base;\n color: @dropdown-link-color;\n white-space: nowrap; // prevent links from randomly breaking onto new lines\n }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n &:hover,\n &:focus {\n text-decoration: none;\n color: @dropdown-link-hover-color;\n background-color: @dropdown-link-hover-bg;\n }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-active-color;\n text-decoration: none;\n outline: 0;\n background-color: @dropdown-link-active-bg;\n }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-disabled-color;\n }\n\n // Nuke hover/focus effects\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none; // Remove CSS gradient\n .reset-filter();\n cursor: @cursor-disabled;\n }\n}\n\n// Open state for the dropdown\n.open {\n // Show the menu\n > .dropdown-menu {\n display: block;\n }\n\n // Remove the outline when :focus is triggered\n > a {\n outline: 0;\n }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n left: auto; // Reset the default from `.dropdown-menu`\n right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: @font-size-small;\n line-height: @line-height-base;\n color: @dropdown-header-color;\n white-space: nowrap; // as with > li > a\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n // Reverse the caret\n .caret {\n border-top: 0;\n border-bottom: @caret-width-base solid;\n content: \"\";\n }\n // Different positioning for bottom up menu\n .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 1px;\n }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-right {\n .dropdown-menu {\n .dropdown-menu-right();\n }\n // Necessary for overrides of the default right aligned menu.\n // Will remove come v4 in all likelihood.\n .dropdown-menu-left {\n .dropdown-menu-left();\n }\n }\n}\n","// Horizontal dividers\n//\n// Dividers (basically an hr) within dropdowns and nav lists\n\n.nav-divider(@color: #e5e5e5) {\n height: 1px;\n margin: ((@line-height-computed / 2) - 1) 0;\n overflow: hidden;\n background-color: @color;\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n","//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle; // match .btn alignment given font-size hack above\n > .btn {\n position: relative;\n float: left;\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active,\n &.active {\n z-index: 2;\n }\n }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n .btn + .btn,\n .btn + .btn-group,\n .btn-group + .btn,\n .btn-group + .btn-group {\n margin-left: -1px;\n }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n margin-left: -5px; // Offset the first child's margin\n &:extend(.clearfix all);\n\n .btn-group,\n .input-group {\n float: left;\n }\n > .btn,\n > .btn-group,\n > .input-group {\n margin-left: 5px;\n }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n margin-left: 0;\n &:not(:last-child):not(.dropdown-toggle) {\n .border-right-radius(0);\n }\n}\n// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-right-radius(0);\n }\n}\n.btn-group > .btn-group:last-child > .btn:first-child {\n .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n // Show no shadow for `.btn-link` since it has no other button styles.\n &.btn-link {\n .box-shadow(none);\n }\n}\n\n\n// Reposition the caret\n.btn .caret {\n margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n border-width: @caret-width-large @caret-width-large 0;\n border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n > .btn,\n > .btn-group,\n > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n }\n\n // Clear floats so dropdown menus can be properly placed\n > .btn-group {\n &:extend(.clearfix all);\n > .btn {\n float: none;\n }\n }\n\n > .btn + .btn,\n > .btn + .btn-group,\n > .btn-group + .btn,\n > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n }\n}\n\n.btn-group-vertical > .btn {\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n &:first-child:not(:last-child) {\n border-top-right-radius: @border-radius-base;\n .border-bottom-radius(0);\n }\n &:last-child:not(:first-child) {\n border-bottom-left-radius: @border-radius-base;\n .border-top-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-bottom-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-top-radius(0);\n}\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n > .btn,\n > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n }\n > .btn-group .btn {\n width: 100%;\n }\n\n > .btn-group .dropdown-menu {\n left: auto;\n }\n}\n\n\n// Checkbox and radio options\n//\n// In order to support the browser's form validation feedback, powered by the\n// `required` attribute, we have to \"hide\" the inputs via `clip`. We cannot use\n// `display: none;` or `visibility: hidden;` as that also hides the popover.\n// Simply visually hiding the inputs via `opacity` would leave them clickable in\n// certain cases which is prevented by using `clip` and `pointer-events`.\n// This way, we ensure a DOM element is visible to position the popover from.\n//\n// See https://github.com/twbs/bootstrap/pull/12794 and\n// https://github.com/twbs/bootstrap/pull/14559 for more information.\n\n[data-toggle=\"buttons\"] {\n > .btn,\n > .btn-group > .btn {\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0,0,0,0);\n pointer-events: none;\n }\n }\n}\n","// Single side border-radius\n\n.border-top-radius(@radius) {\n border-top-right-radius: @radius;\n border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n border-bottom-left-radius: @radius;\n border-top-left-radius: @radius;\n}\n","//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n position: relative; // For dropdowns\n display: table;\n border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n // Undo padding and float of grid classes\n &[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n }\n\n .form-control {\n // Ensure that the input is always above the *appended* addon button for\n // proper border colors.\n position: relative;\n z-index: 2;\n\n // IE9 fubars the placeholder attribute in text inputs and the arrows on\n // select elements in input groups. To fix it, we float the input. Details:\n // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n float: left;\n\n width: 100%;\n margin-bottom: 0;\n }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n .input-lg();\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n .input-sm();\n}\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n font-weight: normal;\n line-height: 1;\n color: @input-color;\n text-align: center;\n background-color: @input-group-addon-bg;\n border: 1px solid @input-group-addon-border-color;\n border-radius: @border-radius-base;\n\n // Sizing\n &.input-sm {\n padding: @padding-small-vertical @padding-small-horizontal;\n font-size: @font-size-small;\n border-radius: @border-radius-small;\n }\n &.input-lg {\n padding: @padding-large-vertical @padding-large-horizontal;\n font-size: @font-size-large;\n border-radius: @border-radius-large;\n }\n\n // Nuke default margins from checkboxes and radios to vertically center within.\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n margin-top: 0;\n }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n .border-right-radius(0);\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n .border-left-radius(0);\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n position: relative;\n // Jankily prevent input button groups from wrapping with `white-space` and\n // `font-size` in combination with `inline-block` on buttons.\n font-size: 0;\n white-space: nowrap;\n\n // Negative margin for spacing, position for bringing hovered/focused/actived\n // element above the siblings.\n > .btn {\n position: relative;\n + .btn {\n margin-left: -1px;\n }\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active {\n z-index: 2;\n }\n }\n\n // Negative margin to only have a 1px border between the two\n &:first-child {\n > .btn,\n > .btn-group {\n margin-right: -1px;\n }\n }\n &:last-child {\n > .btn,\n > .btn-group {\n margin-left: -1px;\n }\n }\n}\n","//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n margin-bottom: 0;\n padding-left: 0; // Override default ul/ol\n list-style: none;\n &:extend(.clearfix all);\n\n > li {\n position: relative;\n display: block;\n\n > a {\n position: relative;\n display: block;\n padding: @nav-link-padding;\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: @nav-link-hover-bg;\n }\n }\n\n // Disabled state sets text to gray and nukes hover/tab effects\n &.disabled > a {\n color: @nav-disabled-link-color;\n\n &:hover,\n &:focus {\n color: @nav-disabled-link-hover-color;\n text-decoration: none;\n background-color: transparent;\n cursor: @cursor-disabled;\n }\n }\n }\n\n // Open dropdowns\n .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @nav-link-hover-bg;\n border-color: @link-color;\n }\n }\n\n // Nav dividers (deprecated with v3.0.1)\n //\n // This should have been removed in v3 with the dropping of `.nav-list`, but\n // we missed it. We don't currently support this anywhere, but in the interest\n // of maintaining backward compatibility in case you use it, it's deprecated.\n .nav-divider {\n .nav-divider();\n }\n\n // Prevent IE8 from misplacing imgs\n //\n // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n > li > a > img {\n max-width: none;\n }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n border-bottom: 1px solid @nav-tabs-border-color;\n > li {\n float: left;\n // Make the list-items overlay the bottom border\n margin-bottom: -1px;\n\n // Actual tabs (as links)\n > a {\n margin-right: 2px;\n line-height: @line-height-base;\n border: 1px solid transparent;\n border-radius: @border-radius-base @border-radius-base 0 0;\n &:hover {\n border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n }\n }\n\n // Active state, and its :hover to override normal :hover\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-tabs-active-link-hover-color;\n background-color: @nav-tabs-active-link-hover-bg;\n border: 1px solid @nav-tabs-active-link-hover-border-color;\n border-bottom-color: transparent;\n cursor: default;\n }\n }\n }\n // pulling this in mainly for less shorthand\n &.nav-justified {\n .nav-justified();\n .nav-tabs-justified();\n }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n > li {\n float: left;\n\n // Links rendered as pills\n > a {\n border-radius: @nav-pills-border-radius;\n }\n + li {\n margin-left: 2px;\n }\n\n // Active state\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-pills-active-link-hover-color;\n background-color: @nav-pills-active-link-hover-bg;\n }\n }\n }\n}\n\n\n// Stacked pills\n.nav-stacked {\n > li {\n float: none;\n + li {\n margin-top: 2px;\n margin-left: 0; // no need for this gap between nav items\n }\n }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n width: 100%;\n\n > li {\n float: none;\n > a {\n text-align: center;\n margin-bottom: 5px;\n }\n }\n\n > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n }\n\n @media (min-width: @screen-sm-min) {\n > li {\n display: table-cell;\n width: 1%;\n > a {\n margin-bottom: 0;\n }\n }\n }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n border-bottom: 0;\n\n > li > a {\n // Override margin from .nav-tabs\n margin-right: 0;\n border-radius: @border-radius-base;\n }\n\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border: 1px solid @nav-tabs-justified-link-border-color;\n }\n\n @media (min-width: @screen-sm-min) {\n > li > a {\n border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n border-radius: @border-radius-base @border-radius-base 0 0;\n }\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border-bottom-color: @nav-tabs-justified-active-link-border-color;\n }\n }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n > .tab-pane {\n display: none;\n visibility: hidden;\n }\n > .active {\n display: block;\n visibility: visible;\n }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n // make dropdown border overlap tab border\n margin-top: -1px;\n // Remove the top rounded corners here since there is a hard edge above the menu\n .border-top-radius(0);\n}\n","//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n position: relative;\n min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n margin-bottom: @navbar-margin-bottom;\n border: 1px solid transparent;\n\n // Prevent floats from breaking the navbar\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: @navbar-border-radius;\n }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n overflow-x: visible;\n padding-right: @navbar-padding-horizontal;\n padding-left: @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n &:extend(.clearfix all);\n -webkit-overflow-scrolling: touch;\n\n &.in {\n overflow-y: auto;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border-top: 0;\n box-shadow: none;\n\n &.collapse {\n display: block !important;\n visibility: visible !important;\n height: auto !important;\n padding-bottom: 0; // Override default setting\n overflow: visible !important;\n }\n\n &.in {\n overflow-y: visible;\n }\n\n // Undo the collapse side padding for navbars with containers to ensure\n // alignment of right-aligned contents.\n .navbar-fixed-top &,\n .navbar-static-top &,\n .navbar-fixed-bottom & {\n padding-left: 0;\n padding-right: 0;\n }\n }\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n .navbar-collapse {\n max-height: @navbar-collapse-max-height;\n\n @media (max-device-width: @screen-xs-min) and (orientation: landscape) {\n max-height: 200px;\n }\n }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n > .navbar-header,\n > .navbar-collapse {\n margin-right: -@navbar-padding-horizontal;\n margin-left: -@navbar-padding-horizontal;\n\n @media (min-width: @grid-float-breakpoint) {\n margin-right: 0;\n margin-left: 0;\n }\n }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n z-index: @zindex-navbar;\n border-width: 0 0 1px;\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: @zindex-navbar-fixed;\n\n // Undo the rounded corners\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0; // override .navbar defaults\n border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n float: left;\n padding: @navbar-padding-vertical @navbar-padding-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-computed;\n height: @navbar-height;\n\n &:hover,\n &:focus {\n text-decoration: none;\n }\n\n > img {\n display: block;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n .navbar > .container &,\n .navbar > .container-fluid & {\n margin-left: -@navbar-padding-horizontal;\n }\n }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: @navbar-padding-horizontal;\n padding: 9px 10px;\n .navbar-vertical-align(34px);\n background-color: transparent;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n border-radius: @border-radius-base;\n\n // We remove the `outline` here, but later compensate by attaching `:hover`\n // styles to `:focus`.\n &:focus {\n outline: 0;\n }\n\n // Bars\n .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n }\n .icon-bar + .icon-bar {\n margin-top: 4px;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n display: none;\n }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: @line-height-computed;\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n > li > a,\n .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n > li > a {\n line-height: @line-height-computed;\n &:hover,\n &:focus {\n background-image: none;\n }\n }\n }\n }\n\n // Uncollapse the nav\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin: 0;\n\n > li {\n float: left;\n > a {\n padding-top: @navbar-padding-vertical;\n padding-bottom: @navbar-padding-vertical;\n }\n }\n }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n margin-left: -@navbar-padding-horizontal;\n margin-right: -@navbar-padding-horizontal;\n padding: 10px @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n\n // Mixin behavior for optimum display\n .form-inline();\n\n .form-group {\n @media (max-width: @grid-float-breakpoint-max) {\n margin-bottom: 5px;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n }\n\n // Vertically center in expanded, horizontal navbar\n .navbar-vertical-align(@input-height-base);\n\n // Undo 100% width for pull classes\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n .box-shadow(none);\n }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n .border-top-radius(@navbar-border-radius);\n .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n .navbar-vertical-align(@input-height-base);\n\n &.btn-sm {\n .navbar-vertical-align(@input-height-small);\n }\n &.btn-xs {\n .navbar-vertical-align(22);\n }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n .navbar-vertical-align(@line-height-computed);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin-left: @navbar-padding-horizontal;\n margin-right: @navbar-padding-horizontal;\n }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n//\n// Declared after the navbar components to ensure more specificity on the margins.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-left { .pull-left(); }\n .navbar-right {\n .pull-right();\n margin-right: -@navbar-padding-horizontal;\n\n ~ .navbar-right {\n margin-right: 0;\n }\n }\n}\n\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n background-color: @navbar-default-bg;\n border-color: @navbar-default-border;\n\n .navbar-brand {\n color: @navbar-default-brand-color;\n &:hover,\n &:focus {\n color: @navbar-default-brand-hover-color;\n background-color: @navbar-default-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-default-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-default-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n\n .navbar-toggle {\n border-color: @navbar-default-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-default-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-default-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: @navbar-default-border;\n }\n\n // Dropdown menu items\n .navbar-nav {\n // Remove background color from open dropdown\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-default-link-active-bg;\n color: @navbar-default-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n > li > a {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n }\n }\n\n\n // Links in navbars\n //\n // Add a class to ensure links outside the navbar nav are colored correctly.\n\n .navbar-link {\n color: @navbar-default-link-color;\n &:hover {\n color: @navbar-default-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n }\n }\n }\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n background-color: @navbar-inverse-bg;\n border-color: @navbar-inverse-border;\n\n .navbar-brand {\n color: @navbar-inverse-brand-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-brand-hover-color;\n background-color: @navbar-inverse-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-inverse-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-inverse-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n\n // Darken the responsive nav toggle\n .navbar-toggle {\n border-color: @navbar-inverse-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-inverse-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-inverse-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: darken(@navbar-inverse-bg, 7%);\n }\n\n // Dropdowns\n .navbar-nav {\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-inverse-link-active-bg;\n color: @navbar-inverse-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display\n .open .dropdown-menu {\n > .dropdown-header {\n border-color: @navbar-inverse-border;\n }\n .divider {\n background-color: @navbar-inverse-border;\n }\n > li > a {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n }\n }\n\n .navbar-link {\n color: @navbar-inverse-link-color;\n &:hover {\n color: @navbar-inverse-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n }\n }\n }\n}\n","// Navbar vertical align\n//\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n\n.navbar-vertical-align(@element-height) {\n margin-top: ((@navbar-height - @element-height) / 2);\n margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n","//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n .clearfix();\n}\n.center-block {\n .center-block();\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n display: none !important;\n visibility: hidden !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n margin-bottom: @line-height-computed;\n list-style: none;\n background-color: @breadcrumb-bg;\n border-radius: @border-radius-base;\n\n > li {\n display: inline-block;\n\n + li:before {\n content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n padding: 0 5px;\n color: @breadcrumb-color;\n }\n }\n\n > .active {\n color: @breadcrumb-active-color;\n }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: @line-height-computed 0;\n border-radius: @border-radius-base;\n\n > li {\n display: inline; // Remove list-style and block-level defaults\n > a,\n > span {\n position: relative;\n float: left; // Collapse white-space\n padding: @padding-base-vertical @padding-base-horizontal;\n line-height: @line-height-base;\n text-decoration: none;\n color: @pagination-color;\n background-color: @pagination-bg;\n border: 1px solid @pagination-border;\n margin-left: -1px;\n }\n &:first-child {\n > a,\n > span {\n margin-left: 0;\n .border-left-radius(@border-radius-base);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius-base);\n }\n }\n }\n\n > li > a,\n > li > span {\n &:hover,\n &:focus {\n color: @pagination-hover-color;\n background-color: @pagination-hover-bg;\n border-color: @pagination-hover-border;\n }\n }\n\n > .active > a,\n > .active > span {\n &,\n &:hover,\n &:focus {\n z-index: 2;\n color: @pagination-active-color;\n background-color: @pagination-active-bg;\n border-color: @pagination-active-border;\n cursor: default;\n }\n }\n\n > .disabled {\n > span,\n > span:hover,\n > span:focus,\n > a,\n > a:hover,\n > a:focus {\n color: @pagination-disabled-color;\n background-color: @pagination-disabled-bg;\n border-color: @pagination-disabled-border;\n cursor: @cursor-disabled;\n }\n }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @border-radius-small);\n}\n","// Pagination\n\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {\n > li {\n > a,\n > span {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n }\n &:first-child {\n > a,\n > span {\n .border-left-radius(@border-radius);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius);\n }\n }\n }\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n padding-left: 0;\n margin: @line-height-computed 0;\n list-style: none;\n text-align: center;\n &:extend(.clearfix all);\n li {\n display: inline;\n > a,\n > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: @pager-bg;\n border: 1px solid @pager-border;\n border-radius: @pager-border-radius;\n }\n\n > a:hover,\n > a:focus {\n text-decoration: none;\n background-color: @pager-hover-bg;\n }\n }\n\n .next {\n > a,\n > span {\n float: right;\n }\n }\n\n .previous {\n > a,\n > span {\n float: left;\n }\n }\n\n .disabled {\n > a,\n > a:hover,\n > a:focus,\n > span {\n color: @pager-disabled-color;\n background-color: @pager-bg;\n cursor: @cursor-disabled;\n }\n }\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: @label-color;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n\n // Add hover effects, but only for links\n a& {\n &:hover,\n &:focus {\n color: @label-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Empty labels collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for labels in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n .label-variant(@label-default-bg);\n}\n\n.label-primary {\n .label-variant(@label-primary-bg);\n}\n\n.label-success {\n .label-variant(@label-success-bg);\n}\n\n.label-info {\n .label-variant(@label-info-bg);\n}\n\n.label-warning {\n .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n .label-variant(@label-danger-bg);\n}\n","// Labels\n\n.label-variant(@color) {\n background-color: @color;\n\n &[href] {\n &:hover,\n &:focus {\n background-color: darken(@color, 10%);\n }\n }\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base class\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: @font-size-small;\n font-weight: @badge-font-weight;\n color: @badge-color;\n line-height: @badge-line-height;\n vertical-align: baseline;\n white-space: nowrap;\n text-align: center;\n background-color: @badge-bg;\n border-radius: @badge-border-radius;\n\n // Empty badges collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for badges in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n .btn-xs & {\n top: 0;\n padding: 1px 5px;\n }\n\n // Hover state, but only for links\n a& {\n &:hover,\n &:focus {\n color: @badge-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Account for badges in navs\n .list-group-item.active > &,\n .nav-pills > .active > a > & {\n color: @badge-active-color;\n background-color: @badge-active-bg;\n }\n .list-group-item > & {\n float: right;\n }\n .list-group-item > & + & {\n margin-right: 5px;\n }\n .nav-pills > li > a > & {\n margin-left: 3px;\n }\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n padding: @jumbotron-padding (@jumbotron-padding / 2);\n margin-bottom: @jumbotron-padding;\n color: @jumbotron-color;\n background-color: @jumbotron-bg;\n\n h1,\n .h1 {\n color: @jumbotron-heading-color;\n }\n p {\n margin-bottom: (@jumbotron-padding / 2);\n font-size: @jumbotron-font-size;\n font-weight: 200;\n }\n\n > hr {\n border-top-color: darken(@jumbotron-bg, 10%);\n }\n\n .container &,\n .container-fluid & {\n border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n }\n\n .container {\n max-width: 100%;\n }\n\n @media screen and (min-width: @screen-sm-min) {\n padding: (@jumbotron-padding * 1.6) 0;\n\n .container &,\n .container-fluid & {\n padding-left: (@jumbotron-padding * 2);\n padding-right: (@jumbotron-padding * 2);\n }\n\n h1,\n .h1 {\n font-size: (@font-size-base * 4.5);\n }\n }\n}\n","//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n display: block;\n padding: @thumbnail-padding;\n margin-bottom: @line-height-computed;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(border .2s ease-in-out);\n\n > img,\n a > img {\n &:extend(.img-responsive);\n margin-left: auto;\n margin-right: auto;\n }\n\n // Add a hover state for linked versions only\n a&:hover,\n a&:focus,\n a&.active {\n border-color: @link-color;\n }\n\n // Image captions\n .caption {\n padding: @thumbnail-caption-padding;\n color: @thumbnail-caption-color;\n }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n padding: @alert-padding;\n margin-bottom: @line-height-computed;\n border: 1px solid transparent;\n border-radius: @alert-border-radius;\n\n // Headings for larger alerts\n h4 {\n margin-top: 0;\n // Specified for the h4 to prevent conflicts of changing @headings-color\n color: inherit;\n }\n // Provide class for links that match alerts\n .alert-link {\n font-weight: @alert-link-font-weight;\n }\n\n // Improve alignment and spacing of inner content\n > p,\n > ul {\n margin-bottom: 0;\n }\n > p + p {\n margin-top: 5px;\n }\n}\n\n// Dismissible alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.\n.alert-dismissible {\n padding-right: (@alert-padding + 20);\n\n // Adjust close link position\n .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n.alert-info {\n .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n.alert-warning {\n .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n.alert-danger {\n .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","// Alerts\n\n.alert-variant(@background; @border; @text-color) {\n background-color: @background;\n border-color: @border;\n color: @text-color;\n\n hr {\n border-top-color: darken(@border, 5%);\n }\n .alert-link {\n color: darken(@text-color, 10%);\n }\n}\n","//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n overflow: hidden;\n height: @line-height-computed;\n margin-bottom: @line-height-computed;\n background-color: @progress-bg;\n border-radius: @progress-border-radius;\n .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: @font-size-small;\n line-height: @line-height-computed;\n color: @progress-bar-color;\n text-align: center;\n background-color: @progress-bar-bg;\n .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n .transition(width .6s ease);\n}\n\n// Striped bars\n//\n// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar-striped` class, which you just add to an existing\n// `.progress-bar`.\n.progress-striped .progress-bar,\n.progress-bar-striped {\n #gradient > .striped();\n background-size: 40px 40px;\n}\n\n// Call animation for the active one\n//\n// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar.active` approach.\n.progress.active .progress-bar,\n.progress-bar.active {\n .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Progress bars\n\n.progress-bar-variant(@color) {\n background-color: @color;\n\n // Deprecated parent class requirement as of v3.2.0\n .progress-striped & {\n #gradient > .striped();\n }\n}\n",".media {\n // Proper spacing between instances of .media\n margin-top: 15px;\n\n &:first-child {\n margin-top: 0;\n }\n}\n\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n\n.media-middle {\n vertical-align: middle;\n}\n\n.media-bottom {\n vertical-align: bottom;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n\n// Media list variation\n//\n// Undo default ul/ol styles\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n","//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on <ul>, <ol>, or <div>.\n\n.list-group {\n // No need to set list-style: none; since .list-group-item is block level\n margin-bottom: 20px;\n padding-left: 0; // reset padding because ul and ol\n}\n\n\n// Individual list items\n//\n// Use on `li`s or `div`s within the `.list-group` parent.\n\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n // Place the border on the list items and negative margin up for better styling\n margin-bottom: -1px;\n background-color: @list-group-bg;\n border: 1px solid @list-group-border;\n\n // Round the first and last items\n &:first-child {\n .border-top-radius(@list-group-border-radius);\n }\n &:last-child {\n margin-bottom: 0;\n .border-bottom-radius(@list-group-border-radius);\n }\n}\n\n\n// Linked list items\n//\n// Use anchor elements instead of `li`s or `div`s to create linked list items.\n// Includes an extra `.active` modifier class for showing selected items.\n\na.list-group-item {\n color: @list-group-link-color;\n\n .list-group-item-heading {\n color: @list-group-link-heading-color;\n }\n\n // Hover state\n &:hover,\n &:focus {\n text-decoration: none;\n color: @list-group-link-hover-color;\n background-color: @list-group-hover-bg;\n }\n}\n\n.list-group-item {\n // Disabled state\n &.disabled,\n &.disabled:hover,\n &.disabled:focus {\n background-color: @list-group-disabled-bg;\n color: @list-group-disabled-color;\n cursor: @cursor-disabled;\n\n // Force color to inherit for custom content\n .list-group-item-heading {\n color: inherit;\n }\n .list-group-item-text {\n color: @list-group-disabled-text-color;\n }\n }\n\n // Active class on item itself, not parent\n &.active,\n &.active:hover,\n &.active:focus {\n z-index: 2; // Place active items above their siblings for proper border styling\n color: @list-group-active-color;\n background-color: @list-group-active-bg;\n border-color: @list-group-active-border;\n\n // Force color to inherit for custom content\n .list-group-item-heading,\n .list-group-item-heading > small,\n .list-group-item-heading > .small {\n color: inherit;\n }\n .list-group-item-text {\n color: @list-group-active-text-color;\n }\n }\n}\n\n\n// Contextual variants\n//\n// Add modifier classes to change text and background color on individual items.\n// Organizationally, this must come after the `:hover` states.\n\n.list-group-item-variant(success; @state-success-bg; @state-success-text);\n.list-group-item-variant(info; @state-info-bg; @state-info-text);\n.list-group-item-variant(warning; @state-warning-bg; @state-warning-text);\n.list-group-item-variant(danger; @state-danger-bg; @state-danger-text);\n\n\n// Custom content options\n//\n// Extra classes for creating well-formatted content within `.list-group-item`s.\n\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n","// List Groups\n\n.list-group-item-variant(@state; @background; @color) {\n .list-group-item-@{state} {\n color: @color;\n background-color: @background;\n\n a& {\n color: @color;\n\n .list-group-item-heading {\n color: inherit;\n }\n\n &:hover,\n &:focus {\n color: @color;\n background-color: darken(@background, 5%);\n }\n &.active,\n &.active:hover,\n &.active:focus {\n color: #fff;\n background-color: @color;\n border-color: @color;\n }\n }\n }\n}\n","//\n// Panels\n// --------------------------------------------------\n\n\n// Base class\n.panel {\n margin-bottom: @line-height-computed;\n background-color: @panel-bg;\n border: 1px solid transparent;\n border-radius: @panel-border-radius;\n .box-shadow(0 1px 1px rgba(0,0,0,.05));\n}\n\n// Panel contents\n.panel-body {\n padding: @panel-body-padding;\n &:extend(.clearfix all);\n}\n\n// Optional heading\n.panel-heading {\n padding: @panel-heading-padding;\n border-bottom: 1px solid transparent;\n .border-top-radius((@panel-border-radius - 1));\n\n > .dropdown .dropdown-toggle {\n color: inherit;\n }\n}\n\n// Within heading, strip any `h*` tag of its default margins for spacing.\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: ceil((@font-size-base * 1.125));\n color: inherit;\n\n > a {\n color: inherit;\n }\n}\n\n// Optional footer (stays gray in every modifier class)\n.panel-footer {\n padding: @panel-footer-padding;\n background-color: @panel-footer-bg;\n border-top: 1px solid @panel-inner-border;\n .border-bottom-radius((@panel-border-radius - 1));\n}\n\n\n// List groups in panels\n//\n// By default, space out list group content from panel headings to account for\n// any kind of custom content between the two.\n\n.panel {\n > .list-group,\n > .panel-collapse > .list-group {\n margin-bottom: 0;\n\n .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n }\n\n // Add border top radius for first one\n &:first-child {\n .list-group-item:first-child {\n border-top: 0;\n .border-top-radius((@panel-border-radius - 1));\n }\n }\n // Add border bottom radius for last one\n &:last-child {\n .list-group-item:last-child {\n border-bottom: 0;\n .border-bottom-radius((@panel-border-radius - 1));\n }\n }\n }\n}\n// Collapse space between when there's no additional content.\n.panel-heading + .list-group {\n .list-group-item:first-child {\n border-top-width: 0;\n }\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n\n// Tables in panels\n//\n// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and\n// watch it go full width.\n\n.panel {\n > .table,\n > .table-responsive > .table,\n > .panel-collapse > .table {\n margin-bottom: 0;\n\n caption {\n padding-left: @panel-body-padding;\n padding-right: @panel-body-padding;\n }\n }\n // Add border top radius for first one\n > .table:first-child,\n > .table-responsive:first-child > .table:first-child {\n .border-top-radius((@panel-border-radius - 1));\n\n > thead:first-child,\n > tbody:first-child {\n > tr:first-child {\n border-top-left-radius: (@panel-border-radius - 1);\n border-top-right-radius: (@panel-border-radius - 1);\n\n td:first-child,\n th:first-child {\n border-top-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-top-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n // Add border bottom radius for last one\n > .table:last-child,\n > .table-responsive:last-child > .table:last-child {\n .border-bottom-radius((@panel-border-radius - 1));\n\n > tbody:last-child,\n > tfoot:last-child {\n > tr:last-child {\n border-bottom-left-radius: (@panel-border-radius - 1);\n border-bottom-right-radius: (@panel-border-radius - 1);\n\n td:first-child,\n th:first-child {\n border-bottom-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-bottom-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n > .panel-body + .table,\n > .panel-body + .table-responsive,\n > .table + .panel-body,\n > .table-responsive + .panel-body {\n border-top: 1px solid @table-border-color;\n }\n > .table > tbody:first-child > tr:first-child th,\n > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n }\n > .table-bordered,\n > .table-responsive > .table-bordered {\n border: 0;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n > thead,\n > tbody {\n > tr:first-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n > tbody,\n > tfoot {\n > tr:last-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n }\n > .table-responsive {\n border: 0;\n margin-bottom: 0;\n }\n}\n\n\n// Collapsable panels (aka, accordion)\n//\n// Wrap a series of panels in `.panel-group` to turn them into an accordion with\n// the help of our collapse JavaScript plugin.\n\n.panel-group {\n margin-bottom: @line-height-computed;\n\n // Tighten up margin so it's only between panels\n .panel {\n margin-bottom: 0;\n border-radius: @panel-border-radius;\n\n + .panel {\n margin-top: 5px;\n }\n }\n\n .panel-heading {\n border-bottom: 0;\n\n + .panel-collapse > .panel-body,\n + .panel-collapse > .list-group {\n border-top: 1px solid @panel-inner-border;\n }\n }\n\n .panel-footer {\n border-top: 0;\n + .panel-collapse .panel-body {\n border-bottom: 1px solid @panel-inner-border;\n }\n }\n}\n\n\n// Contextual variations\n.panel-default {\n .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border);\n}\n.panel-primary {\n .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border);\n}\n.panel-success {\n .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border);\n}\n.panel-info {\n .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border);\n}\n.panel-warning {\n .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border);\n}\n.panel-danger {\n .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border);\n}\n","// Panels\n\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n border-color: @border;\n\n & > .panel-heading {\n color: @heading-text-color;\n background-color: @heading-bg-color;\n border-color: @heading-border;\n\n + .panel-collapse > .panel-body {\n border-top-color: @border;\n }\n .badge {\n color: @heading-bg-color;\n background-color: @heading-text-color;\n }\n }\n & > .panel-footer {\n + .panel-collapse > .panel-body {\n border-bottom-color: @border;\n }\n }\n}\n","// Embeds responsive\n//\n// Credit: Nicolas Gallagher and SUIT CSS.\n\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n\n .embed-responsive-item,\n iframe,\n embed,\n object,\n video {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n height: 100%;\n width: 100%;\n border: 0;\n }\n\n // Modifier class for 16:9 aspect ratio\n &.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n }\n\n // Modifier class for 4:3 aspect ratio\n &.embed-responsive-4by3 {\n padding-bottom: 75%;\n }\n}\n","//\n// Wells\n// --------------------------------------------------\n\n\n// Base class\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: @well-bg;\n border: 1px solid @well-border;\n border-radius: @border-radius-base;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));\n blockquote {\n border-color: #ddd;\n border-color: rgba(0,0,0,.15);\n }\n}\n\n// Sizes\n.well-lg {\n padding: 24px;\n border-radius: @border-radius-large;\n}\n.well-sm {\n padding: 9px;\n border-radius: @border-radius-small;\n}\n","//\n// Close icons\n// --------------------------------------------------\n\n\n.close {\n float: right;\n font-size: (@font-size-base * 1.5);\n font-weight: @close-font-weight;\n line-height: 1;\n color: @close-color;\n text-shadow: @close-text-shadow;\n .opacity(.2);\n\n &:hover,\n &:focus {\n color: @close-color;\n text-decoration: none;\n cursor: pointer;\n .opacity(.5);\n }\n\n // Additional properties for button version\n // iOS requires the button element instead of an anchor tag.\n // If you want the anchor version, it requires `href=\"#\"`.\n button& {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n }\n}\n","//\n// Modals\n// --------------------------------------------------\n\n// .modal-open - body class for killing the scroll\n// .modal - container to scroll within\n// .modal-dialog - positioning shell for the actual modal\n// .modal-content - actual modal w/ bg and corners and shit\n\n// Kill the scroll on the body\n.modal-open {\n overflow: hidden;\n}\n\n// Container that the modal scrolls within\n.modal {\n display: none;\n overflow: hidden;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: @zindex-modal;\n -webkit-overflow-scrolling: touch;\n\n // Prevent Chrome on Windows from adding a focus outline. For details, see\n // https://github.com/twbs/bootstrap/pull/10951.\n outline: 0;\n\n // When fading in the modal, animate it to slide down\n &.fade .modal-dialog {\n .translate(0, -25%);\n .transition-transform(~\"0.3s ease-out\");\n }\n &.in .modal-dialog { .translate(0, 0) }\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n// Shell div to position the modal with bottom padding\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n\n// Actual modal\n.modal-content {\n position: relative;\n background-color: @modal-content-bg;\n border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc)\n border: 1px solid @modal-content-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 3px 9px rgba(0,0,0,.5));\n background-clip: padding-box;\n // Remove focus outline from opened modal\n outline: 0;\n}\n\n// Modal background\n.modal-backdrop {\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n background-color: @modal-backdrop-bg;\n // Fade for backdrop\n &.fade { .opacity(0); }\n &.in { .opacity(@modal-backdrop-opacity); }\n}\n\n// Modal header\n// Top section of the modal w/ title and dismiss\n.modal-header {\n padding: @modal-title-padding;\n border-bottom: 1px solid @modal-header-border-color;\n min-height: (@modal-title-padding + @modal-title-line-height);\n}\n// Close icon\n.modal-header .close {\n margin-top: -2px;\n}\n\n// Title text within header\n.modal-title {\n margin: 0;\n line-height: @modal-title-line-height;\n}\n\n// Modal body\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\n.modal-body {\n position: relative;\n padding: @modal-inner-padding;\n}\n\n// Footer (for actions)\n.modal-footer {\n padding: @modal-inner-padding;\n text-align: right; // right align buttons\n border-top: 1px solid @modal-footer-border-color;\n &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons\n\n // Properly space out buttons\n .btn + .btn {\n margin-left: 5px;\n margin-bottom: 0; // account for input[type=\"submit\"] which gets the bottom margin like all other inputs\n }\n // but override that for button groups\n .btn-group .btn + .btn {\n margin-left: -1px;\n }\n // and override it for block buttons as well\n .btn-block + .btn-block {\n margin-left: 0;\n }\n}\n\n// Measure scrollbar width for padding body during modal show/hide\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n\n// Scale up the modal\n@media (min-width: @screen-sm-min) {\n // Automatically set modal's width for larger viewports\n .modal-dialog {\n width: @modal-md;\n margin: 30px auto;\n }\n .modal-content {\n .box-shadow(0 5px 15px rgba(0,0,0,.5));\n }\n\n // Modal sizes\n .modal-sm { width: @modal-sm; }\n}\n\n@media (min-width: @screen-md-min) {\n .modal-lg { width: @modal-lg; }\n}\n","//\n// Tooltips\n// --------------------------------------------------\n\n\n// Base class\n.tooltip {\n position: absolute;\n z-index: @zindex-tooltip;\n display: block;\n visibility: visible;\n // Reset font and text propertes given new insertion method\n font-family: @font-family-base;\n font-size: @font-size-small;\n font-weight: normal;\n line-height: 1.4;\n .opacity(0);\n\n &.in { .opacity(@tooltip-opacity); }\n &.top { margin-top: -3px; padding: @tooltip-arrow-width 0; }\n &.right { margin-left: 3px; padding: 0 @tooltip-arrow-width; }\n &.bottom { margin-top: 3px; padding: @tooltip-arrow-width 0; }\n &.left { margin-left: -3px; padding: 0 @tooltip-arrow-width; }\n}\n\n// Wrapper for the tooltip content\n.tooltip-inner {\n max-width: @tooltip-max-width;\n padding: 3px 8px;\n color: @tooltip-color;\n text-align: center;\n text-decoration: none;\n background-color: @tooltip-bg;\n border-radius: @border-radius-base;\n}\n\n// Arrows\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n// Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1\n.tooltip {\n &.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-left .tooltip-arrow {\n bottom: 0;\n right: @tooltip-arrow-width;\n margin-bottom: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-right .tooltip-arrow {\n bottom: 0;\n left: @tooltip-arrow-width;\n margin-bottom: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;\n border-right-color: @tooltip-arrow-color;\n }\n &.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-left-color: @tooltip-arrow-color;\n }\n &.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-left .tooltip-arrow {\n top: 0;\n right: @tooltip-arrow-width;\n margin-top: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-right .tooltip-arrow {\n top: 0;\n left: @tooltip-arrow-width;\n margin-top: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n}\n","//\n// Popovers\n// --------------------------------------------------\n\n\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: @zindex-popover;\n display: none;\n max-width: @popover-max-width;\n padding: 1px;\n // Reset font and text propertes given new insertion method\n font-family: @font-family-base;\n font-size: @font-size-base;\n font-weight: normal;\n line-height: @line-height-base;\n text-align: left;\n background-color: @popover-bg;\n background-clip: padding-box;\n border: 1px solid @popover-fallback-border-color;\n border: 1px solid @popover-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 5px 10px rgba(0,0,0,.2));\n\n // Overrides for proper insertion\n white-space: normal;\n\n // Offset the popover to account for the popover arrow\n &.top { margin-top: -@popover-arrow-width; }\n &.right { margin-left: @popover-arrow-width; }\n &.bottom { margin-top: @popover-arrow-width; }\n &.left { margin-left: -@popover-arrow-width; }\n}\n\n.popover-title {\n margin: 0; // reset heading margin\n padding: 8px 14px;\n font-size: @font-size-base;\n background-color: @popover-title-bg;\n border-bottom: 1px solid darken(@popover-title-bg, 5%);\n border-radius: (@border-radius-large - 1) (@border-radius-large - 1) 0 0;\n}\n\n.popover-content {\n padding: 9px 14px;\n}\n\n// Arrows\n//\n// .arrow is outer, .arrow:after is inner\n\n.popover > .arrow {\n &,\n &:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n }\n}\n.popover > .arrow {\n border-width: @popover-arrow-outer-width;\n}\n.popover > .arrow:after {\n border-width: @popover-arrow-width;\n content: \"\";\n}\n\n.popover {\n &.top > .arrow {\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-bottom-width: 0;\n border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-top-color: @popover-arrow-outer-color;\n bottom: -@popover-arrow-outer-width;\n &:after {\n content: \" \";\n bottom: 1px;\n margin-left: -@popover-arrow-width;\n border-bottom-width: 0;\n border-top-color: @popover-arrow-color;\n }\n }\n &.right > .arrow {\n top: 50%;\n left: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-left-width: 0;\n border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-right-color: @popover-arrow-outer-color;\n &:after {\n content: \" \";\n left: 1px;\n bottom: -@popover-arrow-width;\n border-left-width: 0;\n border-right-color: @popover-arrow-color;\n }\n }\n &.bottom > .arrow {\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-top-width: 0;\n border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-bottom-color: @popover-arrow-outer-color;\n top: -@popover-arrow-outer-width;\n &:after {\n content: \" \";\n top: 1px;\n margin-left: -@popover-arrow-width;\n border-top-width: 0;\n border-bottom-color: @popover-arrow-color;\n }\n }\n\n &.left > .arrow {\n top: 50%;\n right: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-right-width: 0;\n border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-left-color: @popover-arrow-outer-color;\n &:after {\n content: \" \";\n right: 1px;\n border-right-width: 0;\n border-left-color: @popover-arrow-color;\n bottom: -@popover-arrow-width;\n }\n }\n}\n","//\n// Carousel\n// --------------------------------------------------\n\n\n// Wrapper for the slide container and indicators\n.carousel {\n position: relative;\n}\n\n.carousel-inner {\n position: relative;\n overflow: hidden;\n width: 100%;\n\n > .item {\n display: none;\n position: relative;\n .transition(.6s ease-in-out left);\n\n // Account for jankitude on images\n > img,\n > a > img {\n &:extend(.img-responsive);\n line-height: 1;\n }\n\n // WebKit CSS3 transforms for supported devices\n @media all and (transform-3d), (-webkit-transform-3d) {\n transition: transform .6s ease-in-out;\n backface-visibility: hidden;\n perspective: 1000;\n\n &.next,\n &.active.right {\n transform: translate3d(100%, 0, 0);\n left: 0;\n }\n &.prev,\n &.active.left {\n transform: translate3d(-100%, 0, 0);\n left: 0;\n }\n &.next.left,\n &.prev.right,\n &.active {\n transform: translate3d(0, 0, 0);\n left: 0;\n }\n }\n }\n\n > .active,\n > .next,\n > .prev {\n display: block;\n }\n\n > .active {\n left: 0;\n }\n\n > .next,\n > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n }\n\n > .next {\n left: 100%;\n }\n > .prev {\n left: -100%;\n }\n > .next.left,\n > .prev.right {\n left: 0;\n }\n\n > .active.left {\n left: -100%;\n }\n > .active.right {\n left: 100%;\n }\n\n}\n\n// Left/right controls for nav\n// ---------------------------\n\n.carousel-control {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n width: @carousel-control-width;\n .opacity(@carousel-control-opacity);\n font-size: @carousel-control-font-size;\n color: @carousel-control-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n // We can't have this transition here because WebKit cancels the carousel\n // animation if you trip this while in the middle of another animation.\n\n // Set gradients for backgrounds\n &.left {\n #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));\n }\n &.right {\n left: auto;\n right: 0;\n #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));\n }\n\n // Hover/focus state\n &:hover,\n &:focus {\n outline: 0;\n color: @carousel-control-color;\n text-decoration: none;\n .opacity(.9);\n }\n\n // Toggles\n .icon-prev,\n .icon-next,\n .glyphicon-chevron-left,\n .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n z-index: 5;\n display: inline-block;\n }\n .icon-prev,\n .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n }\n .icon-next,\n .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n }\n .icon-prev,\n .icon-next {\n width: 20px;\n height: 20px;\n margin-top: -10px;\n font-family: serif;\n }\n\n\n .icon-prev {\n &:before {\n content: '\\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)\n }\n }\n .icon-next {\n &:before {\n content: '\\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)\n }\n }\n}\n\n// Optional indicator pips\n//\n// Add an unordered list with the following class and add a list item for each\n// slide your carousel holds.\n\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n margin-left: -30%;\n padding-left: 0;\n list-style: none;\n text-align: center;\n\n li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n border: 1px solid @carousel-indicator-border-color;\n border-radius: 10px;\n cursor: pointer;\n\n // IE8-9 hack for event handling\n //\n // Internet Explorer 8-9 does not support clicks on elements without a set\n // `background-color`. We cannot use `filter` since that's not viewed as a\n // background color by the browser. Thus, a hack is needed.\n //\n // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we\n // set alpha transparency for the best results possible.\n background-color: #000 \\9; // IE8\n background-color: rgba(0,0,0,0); // IE9\n }\n .active {\n margin: 0;\n width: 12px;\n height: 12px;\n background-color: @carousel-indicator-active-bg;\n }\n}\n\n// Optional captions\n// -----------------------------\n// Hidden by default for smaller viewports\n.carousel-caption {\n position: absolute;\n left: 15%;\n right: 15%;\n bottom: 20px;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: @carousel-caption-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n & .btn {\n text-shadow: none; // No shadow for button elements in carousel-caption\n }\n}\n\n\n// Scale up controls for tablets and up\n@media screen and (min-width: @screen-sm-min) {\n\n // Scale up the controls a smidge\n .carousel-control {\n .glyphicon-chevron-left,\n .glyphicon-chevron-right,\n .icon-prev,\n .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -15px;\n font-size: 30px;\n }\n .glyphicon-chevron-left,\n .icon-prev {\n margin-left: -15px;\n }\n .glyphicon-chevron-right,\n .icon-next {\n margin-right: -15px;\n }\n }\n\n // Show and left align the captions\n .carousel-caption {\n left: 20%;\n right: 20%;\n padding-bottom: 30px;\n }\n\n // Move up the indicators\n .carousel-indicators {\n bottom: 20px;\n }\n}\n","// Clearfix\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n// contenteditable attribute is included anywhere else in the document.\n// Otherwise it causes space to appear at the top and bottom of elements\n// that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n// `:before` to contain the top-margins of child elements.\n//\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n\n.clearfix() {\n &:before,\n &:after {\n content: \" \"; // 1\n display: table; // 2\n }\n &:after {\n clear: both;\n }\n}\n","// Center-align a block level element\n\n.center-block() {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n","// CSS image replacement\n//\n// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n font: ~\"0/0\" a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n\n// New mixin to use as of v3.0.1\n.text-hide() {\n .hide-text();\n}\n","//\n// Responsive: Utility classes\n// --------------------------------------------------\n\n\n// IE10 in Windows (Phone) 8\n//\n// Support for responsive views via media queries is kind of borked in IE10, for\n// Surface/desktop in split view and for Windows Phone 8. This particular fix\n// must be accompanied by a snippet of JavaScript to sniff the user agent and\n// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at\n// our Getting Started page for more information on this bug.\n//\n// For more information, see the following:\n//\n// Issue: https://github.com/twbs/bootstrap/issues/10497\n// Docs: http://getbootstrap.com/getting-started/#support-ie10-width\n// Source: http://timkadlec.com/2013/01/windows-phone-8-and-device-width/\n// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/\n\n@-ms-viewport {\n width: device-width;\n}\n\n\n// Visibility utilities\n// Note: Deprecated .visible-xs, .visible-sm, .visible-md, and .visible-lg as of v3.2.0\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n .responsive-invisibility();\n}\n\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n\n.visible-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-visibility();\n }\n}\n.visible-xs-block {\n @media (max-width: @screen-xs-max) {\n display: block !important;\n }\n}\n.visible-xs-inline {\n @media (max-width: @screen-xs-max) {\n display: inline !important;\n }\n}\n.visible-xs-inline-block {\n @media (max-width: @screen-xs-max) {\n display: inline-block !important;\n }\n}\n\n.visible-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-visibility();\n }\n}\n.visible-sm-block {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: block !important;\n }\n}\n.visible-sm-inline {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: inline !important;\n }\n}\n.visible-sm-inline-block {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: inline-block !important;\n }\n}\n\n.visible-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-visibility();\n }\n}\n.visible-md-block {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: block !important;\n }\n}\n.visible-md-inline {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: inline !important;\n }\n}\n.visible-md-inline-block {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: inline-block !important;\n }\n}\n\n.visible-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-visibility();\n }\n}\n.visible-lg-block {\n @media (min-width: @screen-lg-min) {\n display: block !important;\n }\n}\n.visible-lg-inline {\n @media (min-width: @screen-lg-min) {\n display: inline !important;\n }\n}\n.visible-lg-inline-block {\n @media (min-width: @screen-lg-min) {\n display: inline-block !important;\n }\n}\n\n.hidden-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-invisibility();\n }\n}\n.hidden-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-invisibility();\n }\n}\n.hidden-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-invisibility();\n }\n}\n.hidden-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-invisibility();\n }\n}\n\n\n// Print utilities\n//\n// Media queries are placed on the inside to be mixin-friendly.\n\n// Note: Deprecated .visible-print as of v3.2.0\n.visible-print {\n .responsive-invisibility();\n\n @media print {\n .responsive-visibility();\n }\n}\n.visible-print-block {\n display: none !important;\n\n @media print {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n\n @media print {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n\n @media print {\n display: inline-block !important;\n }\n}\n\n.hidden-print {\n @media print {\n .responsive-invisibility();\n }\n}\n","// Responsive utilities\n\n//\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n display: block !important;\n table& { display: table; }\n tr& { display: table-row !important; }\n th&,\n td& { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n display: none !important;\n}\n"]} \ No newline at end of file
diff --git a/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap.min.css b/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap.min.css
new file mode 100644
index 00000000..b6fe4e0f
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/bootstrap/css/bootstrap.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:before,:after{color:#000!important;text-shadow:none!important;background:transparent!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before,.glyphicon-eur:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}mark,.mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px}input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{position:absolute;margin-top:4px \9;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],input[type=radio].disabled,input[type=checkbox].disabled,fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm,.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm,select.form-group-sm .form-control{height:30px;line-height:30px}textarea.input-sm,textarea.form-group-sm .form-control,select[multiple].input-sm,select[multiple].form-group-sm .form-control{height:auto}.input-lg,.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg,select.form-group-lg .form-control{height:46px;line-height:46px}textarea.input-lg,textarea.form-group-lg .form-control,select[multiple].input-lg,select[multiple].form-group-lg .form-control{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.3px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default.focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary:hover,.btn-primary:focus,.btn-primary.focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success.focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info.focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning.focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger.focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none;visibility:hidden}.collapse.in{display:block;visibility:visible}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#777}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=radio],[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none;visibility:hidden}.tab-content>.active{display:block;visibility:visible}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important;visibility:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:hover,.label-default[href]:focus{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-left,.media-right,.media-body{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table caption,.panel>.table-responsive>.table caption,.panel>.panel-collapse>.table caption{padding-right:15px;padding-left:15px}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body,.panel-group .panel-heading+.panel-collapse>.list-group{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:absolute;top:0;right:0;left:0;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-weight:400;line-height:1.4;visibility:visible;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-weight:400;line-height:1.42857143;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.next,.carousel-inner>.item.active.right{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.prev,.carousel-inner>.item.active.left{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{display:table;content:" "}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none!important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} \ No newline at end of file
diff --git a/libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eot b/libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 00000000..4a4ca865
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eot
Binary files differ
diff --git a/libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.svg b/libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 00000000..25691af8
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,229 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
+<font-face units-per-em="1200" ascent="960" descent="-240" />
+<missing-glyph horiz-adv-x="500" />
+<glyph />
+<glyph />
+<glyph unicode="&#xd;" />
+<glyph unicode=" " />
+<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
+<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
+<glyph unicode="&#xa0;" />
+<glyph unicode="&#x2000;" horiz-adv-x="652" />
+<glyph unicode="&#x2001;" horiz-adv-x="1304" />
+<glyph unicode="&#x2002;" horiz-adv-x="652" />
+<glyph unicode="&#x2003;" horiz-adv-x="1304" />
+<glyph unicode="&#x2004;" horiz-adv-x="434" />
+<glyph unicode="&#x2005;" horiz-adv-x="326" />
+<glyph unicode="&#x2006;" horiz-adv-x="217" />
+<glyph unicode="&#x2007;" horiz-adv-x="217" />
+<glyph unicode="&#x2008;" horiz-adv-x="163" />
+<glyph unicode="&#x2009;" horiz-adv-x="260" />
+<glyph unicode="&#x200a;" horiz-adv-x="72" />
+<glyph unicode="&#x202f;" horiz-adv-x="260" />
+<glyph unicode="&#x205f;" horiz-adv-x="326" />
+<glyph unicode="&#x20ac;" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
+<glyph unicode="&#x2212;" d="M200 400h900v300h-900v-300z" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#x2601;" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
+<glyph unicode="&#x2709;" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
+<glyph unicode="&#x270f;" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
+<glyph unicode="&#xe001;" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
+<glyph unicode="&#xe002;" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
+<glyph unicode="&#xe003;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
+<glyph unicode="&#xe005;" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
+<glyph unicode="&#xe006;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
+<glyph unicode="&#xe007;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
+<glyph unicode="&#xe008;" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
+<glyph unicode="&#xe009;" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
+<glyph unicode="&#xe010;" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe011;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe012;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe013;" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
+<glyph unicode="&#xe014;" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
+<glyph unicode="&#xe015;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
+<glyph unicode="&#xe016;" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
+<glyph unicode="&#xe017;" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
+<glyph unicode="&#xe018;" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
+<glyph unicode="&#xe019;" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
+<glyph unicode="&#xe020;" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
+<glyph unicode="&#xe021;" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
+<glyph unicode="&#xe022;" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
+<glyph unicode="&#xe023;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
+<glyph unicode="&#xe024;" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
+<glyph unicode="&#xe025;" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
+<glyph unicode="&#xe026;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
+<glyph unicode="&#xe027;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
+<glyph unicode="&#xe028;" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
+<glyph unicode="&#xe029;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
+<glyph unicode="&#xe030;" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
+<glyph unicode="&#xe031;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
+<glyph unicode="&#xe032;" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
+<glyph unicode="&#xe033;" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
+<glyph unicode="&#xe034;" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
+<glyph unicode="&#xe035;" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
+<glyph unicode="&#xe036;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
+<glyph unicode="&#xe037;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
+<glyph unicode="&#xe038;" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
+<glyph unicode="&#xe039;" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
+<glyph unicode="&#xe040;" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
+<glyph unicode="&#xe041;" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
+<glyph unicode="&#xe042;" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
+<glyph unicode="&#xe043;" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
+<glyph unicode="&#xe044;" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
+<glyph unicode="&#xe045;" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
+<glyph unicode="&#xe046;" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
+<glyph unicode="&#xe047;" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
+<glyph unicode="&#xe048;" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
+<glyph unicode="&#xe049;" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
+<glyph unicode="&#xe050;" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
+<glyph unicode="&#xe051;" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
+<glyph unicode="&#xe052;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe053;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe054;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe055;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe056;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe057;" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe058;" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
+<glyph unicode="&#xe059;" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
+<glyph unicode="&#xe060;" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
+<glyph unicode="&#xe062;" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
+<glyph unicode="&#xe063;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
+<glyph unicode="&#xe064;" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
+<glyph unicode="&#xe065;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
+<glyph unicode="&#xe066;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
+<glyph unicode="&#xe067;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
+<glyph unicode="&#xe068;" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
+<glyph unicode="&#xe069;" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe070;" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe071;" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
+<glyph unicode="&#xe072;" d="M200 0l900 550l-900 550v-1100z" />
+<glyph unicode="&#xe073;" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe074;" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe075;" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
+<glyph unicode="&#xe076;" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
+<glyph unicode="&#xe077;" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
+<glyph unicode="&#xe078;" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
+<glyph unicode="&#xe079;" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
+<glyph unicode="&#xe080;" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
+<glyph unicode="&#xe081;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
+<glyph unicode="&#xe082;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
+<glyph unicode="&#xe083;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
+<glyph unicode="&#xe084;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
+<glyph unicode="&#xe085;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" />
+<glyph unicode="&#xe086;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
+<glyph unicode="&#xe087;" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
+<glyph unicode="&#xe088;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
+<glyph unicode="&#xe089;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
+<glyph unicode="&#xe090;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
+<glyph unicode="&#xe091;" d="M0 547l600 453v-300h600v-300h-600v-301z" />
+<glyph unicode="&#xe092;" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
+<glyph unicode="&#xe093;" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
+<glyph unicode="&#xe094;" d="M104 600h296v600h300v-600h298l-449 -600z" />
+<glyph unicode="&#xe095;" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
+<glyph unicode="&#xe096;" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
+<glyph unicode="&#xe097;" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
+<glyph unicode="&#xe101;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
+<glyph unicode="&#xe102;" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
+<glyph unicode="&#xe103;" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
+<glyph unicode="&#xe104;" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
+<glyph unicode="&#xe105;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
+<glyph unicode="&#xe106;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
+<glyph unicode="&#xe107;" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
+<glyph unicode="&#xe108;" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
+<glyph unicode="&#xe109;" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
+<glyph unicode="&#xe110;" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
+<glyph unicode="&#xe111;" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
+<glyph unicode="&#xe112;" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
+<glyph unicode="&#xe113;" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
+<glyph unicode="&#xe114;" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
+<glyph unicode="&#xe115;" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
+<glyph unicode="&#xe116;" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
+<glyph unicode="&#xe117;" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
+<glyph unicode="&#xe118;" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
+<glyph unicode="&#xe119;" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
+<glyph unicode="&#xe120;" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
+<glyph unicode="&#xe121;" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
+<glyph unicode="&#xe122;" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe123;" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
+<glyph unicode="&#xe124;" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
+<glyph unicode="&#xe125;" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
+<glyph unicode="&#xe126;" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
+<glyph unicode="&#xe127;" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
+<glyph unicode="&#xe128;" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
+<glyph unicode="&#xe129;" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
+<glyph unicode="&#xe130;" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
+<glyph unicode="&#xe131;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
+<glyph unicode="&#xe132;" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
+<glyph unicode="&#xe133;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
+<glyph unicode="&#xe134;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
+<glyph unicode="&#xe135;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" />
+<glyph unicode="&#xe136;" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
+<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
+<glyph unicode="&#xe138;" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
+<glyph unicode="&#xe139;" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
+<glyph unicode="&#xe140;" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
+<glyph unicode="&#xe141;" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
+<glyph unicode="&#xe142;" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
+<glyph unicode="&#xe143;" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" />
+<glyph unicode="&#xe144;" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
+<glyph unicode="&#xe145;" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
+<glyph unicode="&#xe146;" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
+<glyph unicode="&#xe148;" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
+<glyph unicode="&#xe149;" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" />
+<glyph unicode="&#xe150;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
+<glyph unicode="&#xe151;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
+<glyph unicode="&#xe152;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
+<glyph unicode="&#xe153;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
+<glyph unicode="&#xe154;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
+<glyph unicode="&#xe155;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
+<glyph unicode="&#xe156;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
+<glyph unicode="&#xe157;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
+<glyph unicode="&#xe158;" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
+<glyph unicode="&#xe159;" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
+<glyph unicode="&#xe160;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
+<glyph unicode="&#xe161;" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
+<glyph unicode="&#xe162;" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
+<glyph unicode="&#xe163;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
+<glyph unicode="&#xe164;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
+<glyph unicode="&#xe165;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
+<glyph unicode="&#xe166;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe167;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe168;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe169;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe170;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe171;" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
+<glyph unicode="&#xe172;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe173;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe174;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
+<glyph unicode="&#xe175;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe176;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe177;" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
+<glyph unicode="&#xe178;" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
+<glyph unicode="&#xe179;" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
+<glyph unicode="&#xe180;" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
+<glyph unicode="&#xe181;" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
+<glyph unicode="&#xe182;" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
+<glyph unicode="&#xe183;" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
+<glyph unicode="&#xe184;" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
+<glyph unicode="&#xe185;" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
+<glyph unicode="&#xe186;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe187;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe188;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
+<glyph unicode="&#xe189;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
+<glyph unicode="&#xe190;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
+<glyph unicode="&#xe191;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe192;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe193;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
+<glyph unicode="&#xe194;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
+<glyph unicode="&#xe195;" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
+<glyph unicode="&#xe197;" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
+<glyph unicode="&#xe198;" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
+<glyph unicode="&#xe199;" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
+<glyph unicode="&#xe200;" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
+</font>
+</defs></svg> \ No newline at end of file
diff --git a/libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttf b/libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 00000000..67fa00bf
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttf
Binary files differ
diff --git a/libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woff b/libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 00000000..8c54182a
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woff
Binary files differ
diff --git a/libccnx-common/documentation/doxygen-extras/bootstrap/js/bootstrap.js b/libccnx-common/documentation/doxygen-extras/bootstrap/js/bootstrap.js
new file mode 100644
index 00000000..b6ac8d99
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/bootstrap/js/bootstrap.js
@@ -0,0 +1,2320 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+if (typeof jQuery === 'undefined') {
+ throw new Error('Bootstrap\'s JavaScript requires jQuery')
+}
+
++function ($) {
+ var version = $.fn.jquery.split(' ')[0].split('.')
+ if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {
+ throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher')
+ }
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: transition.js v3.3.1
+ * http://getbootstrap.com/javascript/#transitions
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
+ // ============================================================
+
+ function transitionEnd() {
+ var el = document.createElement('bootstrap')
+
+ var transEndEventNames = {
+ WebkitTransition : 'webkitTransitionEnd',
+ MozTransition : 'transitionend',
+ OTransition : 'oTransitionEnd otransitionend',
+ transition : 'transitionend'
+ }
+
+ for (var name in transEndEventNames) {
+ if (el.style[name] !== undefined) {
+ return { end: transEndEventNames[name] }
+ }
+ }
+
+ return false // explicit for ie8 ( ._.)
+ }
+
+ // http://blog.alexmaccaw.com/css-transitions
+ $.fn.emulateTransitionEnd = function (duration) {
+ var called = false
+ var $el = this
+ $(this).one('bsTransitionEnd', function () { called = true })
+ var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
+ setTimeout(callback, duration)
+ return this
+ }
+
+ $(function () {
+ $.support.transition = transitionEnd()
+
+ if (!$.support.transition) return
+
+ $.event.special.bsTransitionEnd = {
+ bindType: $.support.transition.end,
+ delegateType: $.support.transition.end,
+ handle: function (e) {
+ if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
+ }
+ }
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: alert.js v3.3.1
+ * http://getbootstrap.com/javascript/#alerts
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // ALERT CLASS DEFINITION
+ // ======================
+
+ var dismiss = '[data-dismiss="alert"]'
+ var Alert = function (el) {
+ $(el).on('click', dismiss, this.close)
+ }
+
+ Alert.VERSION = '3.3.1'
+
+ Alert.TRANSITION_DURATION = 150
+
+ Alert.prototype.close = function (e) {
+ var $this = $(this)
+ var selector = $this.attr('data-target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+ }
+
+ var $parent = $(selector)
+
+ if (e) e.preventDefault()
+
+ if (!$parent.length) {
+ $parent = $this.closest('.alert')
+ }
+
+ $parent.trigger(e = $.Event('close.bs.alert'))
+
+ if (e.isDefaultPrevented()) return
+
+ $parent.removeClass('in')
+
+ function removeElement() {
+ // detach from parent, fire event then clean up data
+ $parent.detach().trigger('closed.bs.alert').remove()
+ }
+
+ $.support.transition && $parent.hasClass('fade') ?
+ $parent
+ .one('bsTransitionEnd', removeElement)
+ .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
+ removeElement()
+ }
+
+
+ // ALERT PLUGIN DEFINITION
+ // =======================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.alert')
+
+ if (!data) $this.data('bs.alert', (data = new Alert(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ var old = $.fn.alert
+
+ $.fn.alert = Plugin
+ $.fn.alert.Constructor = Alert
+
+
+ // ALERT NO CONFLICT
+ // =================
+
+ $.fn.alert.noConflict = function () {
+ $.fn.alert = old
+ return this
+ }
+
+
+ // ALERT DATA-API
+ // ==============
+
+ $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: button.js v3.3.1
+ * http://getbootstrap.com/javascript/#buttons
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // BUTTON PUBLIC CLASS DEFINITION
+ // ==============================
+
+ var Button = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, Button.DEFAULTS, options)
+ this.isLoading = false
+ }
+
+ Button.VERSION = '3.3.1'
+
+ Button.DEFAULTS = {
+ loadingText: 'loading...'
+ }
+
+ Button.prototype.setState = function (state) {
+ var d = 'disabled'
+ var $el = this.$element
+ var val = $el.is('input') ? 'val' : 'html'
+ var data = $el.data()
+
+ state = state + 'Text'
+
+ if (data.resetText == null) $el.data('resetText', $el[val]())
+
+ // push to event loop to allow forms to submit
+ setTimeout($.proxy(function () {
+ $el[val](data[state] == null ? this.options[state] : data[state])
+
+ if (state == 'loadingText') {
+ this.isLoading = true
+ $el.addClass(d).attr(d, d)
+ } else if (this.isLoading) {
+ this.isLoading = false
+ $el.removeClass(d).removeAttr(d)
+ }
+ }, this), 0)
+ }
+
+ Button.prototype.toggle = function () {
+ var changed = true
+ var $parent = this.$element.closest('[data-toggle="buttons"]')
+
+ if ($parent.length) {
+ var $input = this.$element.find('input')
+ if ($input.prop('type') == 'radio') {
+ if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
+ else $parent.find('.active').removeClass('active')
+ }
+ if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
+ } else {
+ this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
+ }
+
+ if (changed) this.$element.toggleClass('active')
+ }
+
+
+ // BUTTON PLUGIN DEFINITION
+ // ========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.button')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.button', (data = new Button(this, options)))
+
+ if (option == 'toggle') data.toggle()
+ else if (option) data.setState(option)
+ })
+ }
+
+ var old = $.fn.button
+
+ $.fn.button = Plugin
+ $.fn.button.Constructor = Button
+
+
+ // BUTTON NO CONFLICT
+ // ==================
+
+ $.fn.button.noConflict = function () {
+ $.fn.button = old
+ return this
+ }
+
+
+ // BUTTON DATA-API
+ // ===============
+
+ $(document)
+ .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+ var $btn = $(e.target)
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
+ Plugin.call($btn, 'toggle')
+ e.preventDefault()
+ })
+ .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+ $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: carousel.js v3.3.1
+ * http://getbootstrap.com/javascript/#carousel
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // CAROUSEL CLASS DEFINITION
+ // =========================
+
+ var Carousel = function (element, options) {
+ this.$element = $(element)
+ this.$indicators = this.$element.find('.carousel-indicators')
+ this.options = options
+ this.paused =
+ this.sliding =
+ this.interval =
+ this.$active =
+ this.$items = null
+
+ this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
+
+ this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
+ .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
+ .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
+ }
+
+ Carousel.VERSION = '3.3.1'
+
+ Carousel.TRANSITION_DURATION = 600
+
+ Carousel.DEFAULTS = {
+ interval: 5000,
+ pause: 'hover',
+ wrap: true,
+ keyboard: true
+ }
+
+ Carousel.prototype.keydown = function (e) {
+ if (/input|textarea/i.test(e.target.tagName)) return
+ switch (e.which) {
+ case 37: this.prev(); break
+ case 39: this.next(); break
+ default: return
+ }
+
+ e.preventDefault()
+ }
+
+ Carousel.prototype.cycle = function (e) {
+ e || (this.paused = false)
+
+ this.interval && clearInterval(this.interval)
+
+ this.options.interval
+ && !this.paused
+ && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
+
+ return this
+ }
+
+ Carousel.prototype.getItemIndex = function (item) {
+ this.$items = item.parent().children('.item')
+ return this.$items.index(item || this.$active)
+ }
+
+ Carousel.prototype.getItemForDirection = function (direction, active) {
+ var delta = direction == 'prev' ? -1 : 1
+ var activeIndex = this.getItemIndex(active)
+ var itemIndex = (activeIndex + delta) % this.$items.length
+ return this.$items.eq(itemIndex)
+ }
+
+ Carousel.prototype.to = function (pos) {
+ var that = this
+ var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
+
+ if (pos > (this.$items.length - 1) || pos < 0) return
+
+ if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
+ if (activeIndex == pos) return this.pause().cycle()
+
+ return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
+ }
+
+ Carousel.prototype.pause = function (e) {
+ e || (this.paused = true)
+
+ if (this.$element.find('.next, .prev').length && $.support.transition) {
+ this.$element.trigger($.support.transition.end)
+ this.cycle(true)
+ }
+
+ this.interval = clearInterval(this.interval)
+
+ return this
+ }
+
+ Carousel.prototype.next = function () {
+ if (this.sliding) return
+ return this.slide('next')
+ }
+
+ Carousel.prototype.prev = function () {
+ if (this.sliding) return
+ return this.slide('prev')
+ }
+
+ Carousel.prototype.slide = function (type, next) {
+ var $active = this.$element.find('.item.active')
+ var $next = next || this.getItemForDirection(type, $active)
+ var isCycling = this.interval
+ var direction = type == 'next' ? 'left' : 'right'
+ var fallback = type == 'next' ? 'first' : 'last'
+ var that = this
+
+ if (!$next.length) {
+ if (!this.options.wrap) return
+ $next = this.$element.find('.item')[fallback]()
+ }
+
+ if ($next.hasClass('active')) return (this.sliding = false)
+
+ var relatedTarget = $next[0]
+ var slideEvent = $.Event('slide.bs.carousel', {
+ relatedTarget: relatedTarget,
+ direction: direction
+ })
+ this.$element.trigger(slideEvent)
+ if (slideEvent.isDefaultPrevented()) return
+
+ this.sliding = true
+
+ isCycling && this.pause()
+
+ if (this.$indicators.length) {
+ this.$indicators.find('.active').removeClass('active')
+ var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
+ $nextIndicator && $nextIndicator.addClass('active')
+ }
+
+ var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
+ if ($.support.transition && this.$element.hasClass('slide')) {
+ $next.addClass(type)
+ $next[0].offsetWidth // force reflow
+ $active.addClass(direction)
+ $next.addClass(direction)
+ $active
+ .one('bsTransitionEnd', function () {
+ $next.removeClass([type, direction].join(' ')).addClass('active')
+ $active.removeClass(['active', direction].join(' '))
+ that.sliding = false
+ setTimeout(function () {
+ that.$element.trigger(slidEvent)
+ }, 0)
+ })
+ .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
+ } else {
+ $active.removeClass('active')
+ $next.addClass('active')
+ this.sliding = false
+ this.$element.trigger(slidEvent)
+ }
+
+ isCycling && this.cycle()
+
+ return this
+ }
+
+
+ // CAROUSEL PLUGIN DEFINITION
+ // ==========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.carousel')
+ var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
+ var action = typeof option == 'string' ? option : options.slide
+
+ if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
+ if (typeof option == 'number') data.to(option)
+ else if (action) data[action]()
+ else if (options.interval) data.pause().cycle()
+ })
+ }
+
+ var old = $.fn.carousel
+
+ $.fn.carousel = Plugin
+ $.fn.carousel.Constructor = Carousel
+
+
+ // CAROUSEL NO CONFLICT
+ // ====================
+
+ $.fn.carousel.noConflict = function () {
+ $.fn.carousel = old
+ return this
+ }
+
+
+ // CAROUSEL DATA-API
+ // =================
+
+ var clickHandler = function (e) {
+ var href
+ var $this = $(this)
+ var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
+ if (!$target.hasClass('carousel')) return
+ var options = $.extend({}, $target.data(), $this.data())
+ var slideIndex = $this.attr('data-slide-to')
+ if (slideIndex) options.interval = false
+
+ Plugin.call($target, options)
+
+ if (slideIndex) {
+ $target.data('bs.carousel').to(slideIndex)
+ }
+
+ e.preventDefault()
+ }
+
+ $(document)
+ .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
+ .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
+
+ $(window).on('load', function () {
+ $('[data-ride="carousel"]').each(function () {
+ var $carousel = $(this)
+ Plugin.call($carousel, $carousel.data())
+ })
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: collapse.js v3.3.1
+ * http://getbootstrap.com/javascript/#collapse
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // COLLAPSE PUBLIC CLASS DEFINITION
+ // ================================
+
+ var Collapse = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, Collapse.DEFAULTS, options)
+ this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]')
+ this.transitioning = null
+
+ if (this.options.parent) {
+ this.$parent = this.getParent()
+ } else {
+ this.addAriaAndCollapsedClass(this.$element, this.$trigger)
+ }
+
+ if (this.options.toggle) this.toggle()
+ }
+
+ Collapse.VERSION = '3.3.1'
+
+ Collapse.TRANSITION_DURATION = 350
+
+ Collapse.DEFAULTS = {
+ toggle: true,
+ trigger: '[data-toggle="collapse"]'
+ }
+
+ Collapse.prototype.dimension = function () {
+ var hasWidth = this.$element.hasClass('width')
+ return hasWidth ? 'width' : 'height'
+ }
+
+ Collapse.prototype.show = function () {
+ if (this.transitioning || this.$element.hasClass('in')) return
+
+ var activesData
+ var actives = this.$parent && this.$parent.find('> .panel').children('.in, .collapsing')
+
+ if (actives && actives.length) {
+ activesData = actives.data('bs.collapse')
+ if (activesData && activesData.transitioning) return
+ }
+
+ var startEvent = $.Event('show.bs.collapse')
+ this.$element.trigger(startEvent)
+ if (startEvent.isDefaultPrevented()) return
+
+ if (actives && actives.length) {
+ Plugin.call(actives, 'hide')
+ activesData || actives.data('bs.collapse', null)
+ }
+
+ var dimension = this.dimension()
+
+ this.$element
+ .removeClass('collapse')
+ .addClass('collapsing')[dimension](0)
+ .attr('aria-expanded', true)
+
+ this.$trigger
+ .removeClass('collapsed')
+ .attr('aria-expanded', true)
+
+ this.transitioning = 1
+
+ var complete = function () {
+ this.$element
+ .removeClass('collapsing')
+ .addClass('collapse in')[dimension]('')
+ this.transitioning = 0
+ this.$element
+ .trigger('shown.bs.collapse')
+ }
+
+ if (!$.support.transition) return complete.call(this)
+
+ var scrollSize = $.camelCase(['scroll', dimension].join('-'))
+
+ this.$element
+ .one('bsTransitionEnd', $.proxy(complete, this))
+ .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
+ }
+
+ Collapse.prototype.hide = function () {
+ if (this.transitioning || !this.$element.hasClass('in')) return
+
+ var startEvent = $.Event('hide.bs.collapse')
+ this.$element.trigger(startEvent)
+ if (startEvent.isDefaultPrevented()) return
+
+ var dimension = this.dimension()
+
+ this.$element[dimension](this.$element[dimension]())[0].offsetHeight
+
+ this.$element
+ .addClass('collapsing')
+ .removeClass('collapse in')
+ .attr('aria-expanded', false)
+
+ this.$trigger
+ .addClass('collapsed')
+ .attr('aria-expanded', false)
+
+ this.transitioning = 1
+
+ var complete = function () {
+ this.transitioning = 0
+ this.$element
+ .removeClass('collapsing')
+ .addClass('collapse')
+ .trigger('hidden.bs.collapse')
+ }
+
+ if (!$.support.transition) return complete.call(this)
+
+ this.$element
+ [dimension](0)
+ .one('bsTransitionEnd', $.proxy(complete, this))
+ .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
+ }
+
+ Collapse.prototype.toggle = function () {
+ this[this.$element.hasClass('in') ? 'hide' : 'show']()
+ }
+
+ Collapse.prototype.getParent = function () {
+ return $(this.options.parent)
+ .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
+ .each($.proxy(function (i, element) {
+ var $element = $(element)
+ this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
+ }, this))
+ .end()
+ }
+
+ Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
+ var isOpen = $element.hasClass('in')
+
+ $element.attr('aria-expanded', isOpen)
+ $trigger
+ .toggleClass('collapsed', !isOpen)
+ .attr('aria-expanded', isOpen)
+ }
+
+ function getTargetFromTrigger($trigger) {
+ var href
+ var target = $trigger.attr('data-target')
+ || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
+
+ return $(target)
+ }
+
+
+ // COLLAPSE PLUGIN DEFINITION
+ // ==========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.collapse')
+ var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+ if (!data && options.toggle && option == 'show') options.toggle = false
+ if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.collapse
+
+ $.fn.collapse = Plugin
+ $.fn.collapse.Constructor = Collapse
+
+
+ // COLLAPSE NO CONFLICT
+ // ====================
+
+ $.fn.collapse.noConflict = function () {
+ $.fn.collapse = old
+ return this
+ }
+
+
+ // COLLAPSE DATA-API
+ // =================
+
+ $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
+ var $this = $(this)
+
+ if (!$this.attr('data-target')) e.preventDefault()
+
+ var $target = getTargetFromTrigger($this)
+ var data = $target.data('bs.collapse')
+ var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this })
+
+ Plugin.call($target, option)
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: dropdown.js v3.3.1
+ * http://getbootstrap.com/javascript/#dropdowns
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // DROPDOWN CLASS DEFINITION
+ // =========================
+
+ var backdrop = '.dropdown-backdrop'
+ var toggle = '[data-toggle="dropdown"]'
+ var Dropdown = function (element) {
+ $(element).on('click.bs.dropdown', this.toggle)
+ }
+
+ Dropdown.VERSION = '3.3.1'
+
+ Dropdown.prototype.toggle = function (e) {
+ var $this = $(this)
+
+ if ($this.is('.disabled, :disabled')) return
+
+ var $parent = getParent($this)
+ var isActive = $parent.hasClass('open')
+
+ clearMenus()
+
+ if (!isActive) {
+ if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
+ // if mobile we use a backdrop because click events don't delegate
+ $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
+ }
+
+ var relatedTarget = { relatedTarget: this }
+ $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
+
+ if (e.isDefaultPrevented()) return
+
+ $this
+ .trigger('focus')
+ .attr('aria-expanded', 'true')
+
+ $parent
+ .toggleClass('open')
+ .trigger('shown.bs.dropdown', relatedTarget)
+ }
+
+ return false
+ }
+
+ Dropdown.prototype.keydown = function (e) {
+ if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
+
+ var $this = $(this)
+
+ e.preventDefault()
+ e.stopPropagation()
+
+ if ($this.is('.disabled, :disabled')) return
+
+ var $parent = getParent($this)
+ var isActive = $parent.hasClass('open')
+
+ if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {
+ if (e.which == 27) $parent.find(toggle).trigger('focus')
+ return $this.trigger('click')
+ }
+
+ var desc = ' li:not(.divider):visible a'
+ var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)
+
+ if (!$items.length) return
+
+ var index = $items.index(e.target)
+
+ if (e.which == 38 && index > 0) index-- // up
+ if (e.which == 40 && index < $items.length - 1) index++ // down
+ if (!~index) index = 0
+
+ $items.eq(index).trigger('focus')
+ }
+
+ function clearMenus(e) {
+ if (e && e.which === 3) return
+ $(backdrop).remove()
+ $(toggle).each(function () {
+ var $this = $(this)
+ var $parent = getParent($this)
+ var relatedTarget = { relatedTarget: this }
+
+ if (!$parent.hasClass('open')) return
+
+ $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
+
+ if (e.isDefaultPrevented()) return
+
+ $this.attr('aria-expanded', 'false')
+ $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
+ })
+ }
+
+ function getParent($this) {
+ var selector = $this.attr('data-target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+ }
+
+ var $parent = selector && $(selector)
+
+ return $parent && $parent.length ? $parent : $this.parent()
+ }
+
+
+ // DROPDOWN PLUGIN DEFINITION
+ // ==========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.dropdown')
+
+ if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ var old = $.fn.dropdown
+
+ $.fn.dropdown = Plugin
+ $.fn.dropdown.Constructor = Dropdown
+
+
+ // DROPDOWN NO CONFLICT
+ // ====================
+
+ $.fn.dropdown.noConflict = function () {
+ $.fn.dropdown = old
+ return this
+ }
+
+
+ // APPLY TO STANDARD DROPDOWN ELEMENTS
+ // ===================================
+
+ $(document)
+ .on('click.bs.dropdown.data-api', clearMenus)
+ .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+ .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+ .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
+ .on('keydown.bs.dropdown.data-api', '[role="menu"]', Dropdown.prototype.keydown)
+ .on('keydown.bs.dropdown.data-api', '[role="listbox"]', Dropdown.prototype.keydown)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: modal.js v3.3.1
+ * http://getbootstrap.com/javascript/#modals
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // MODAL CLASS DEFINITION
+ // ======================
+
+ var Modal = function (element, options) {
+ this.options = options
+ this.$body = $(document.body)
+ this.$element = $(element)
+ this.$backdrop =
+ this.isShown = null
+ this.scrollbarWidth = 0
+
+ if (this.options.remote) {
+ this.$element
+ .find('.modal-content')
+ .load(this.options.remote, $.proxy(function () {
+ this.$element.trigger('loaded.bs.modal')
+ }, this))
+ }
+ }
+
+ Modal.VERSION = '3.3.1'
+
+ Modal.TRANSITION_DURATION = 300
+ Modal.BACKDROP_TRANSITION_DURATION = 150
+
+ Modal.DEFAULTS = {
+ backdrop: true,
+ keyboard: true,
+ show: true
+ }
+
+ Modal.prototype.toggle = function (_relatedTarget) {
+ return this.isShown ? this.hide() : this.show(_relatedTarget)
+ }
+
+ Modal.prototype.show = function (_relatedTarget) {
+ var that = this
+ var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
+
+ this.$element.trigger(e)
+
+ if (this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = true
+
+ this.checkScrollbar()
+ this.setScrollbar()
+ this.$body.addClass('modal-open')
+
+ this.escape()
+ this.resize()
+
+ this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
+
+ this.backdrop(function () {
+ var transition = $.support.transition && that.$element.hasClass('fade')
+
+ if (!that.$element.parent().length) {
+ that.$element.appendTo(that.$body) // don't move modals dom position
+ }
+
+ that.$element
+ .show()
+ .scrollTop(0)
+
+ if (that.options.backdrop) that.adjustBackdrop()
+ that.adjustDialog()
+
+ if (transition) {
+ that.$element[0].offsetWidth // force reflow
+ }
+
+ that.$element
+ .addClass('in')
+ .attr('aria-hidden', false)
+
+ that.enforceFocus()
+
+ var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
+
+ transition ?
+ that.$element.find('.modal-dialog') // wait for modal to slide in
+ .one('bsTransitionEnd', function () {
+ that.$element.trigger('focus').trigger(e)
+ })
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
+ that.$element.trigger('focus').trigger(e)
+ })
+ }
+
+ Modal.prototype.hide = function (e) {
+ if (e) e.preventDefault()
+
+ e = $.Event('hide.bs.modal')
+
+ this.$element.trigger(e)
+
+ if (!this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = false
+
+ this.escape()
+ this.resize()
+
+ $(document).off('focusin.bs.modal')
+
+ this.$element
+ .removeClass('in')
+ .attr('aria-hidden', true)
+ .off('click.dismiss.bs.modal')
+
+ $.support.transition && this.$element.hasClass('fade') ?
+ this.$element
+ .one('bsTransitionEnd', $.proxy(this.hideModal, this))
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
+ this.hideModal()
+ }
+
+ Modal.prototype.enforceFocus = function () {
+ $(document)
+ .off('focusin.bs.modal') // guard against infinite focus loop
+ .on('focusin.bs.modal', $.proxy(function (e) {
+ if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
+ this.$element.trigger('focus')
+ }
+ }, this))
+ }
+
+ Modal.prototype.escape = function () {
+ if (this.isShown && this.options.keyboard) {
+ this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
+ e.which == 27 && this.hide()
+ }, this))
+ } else if (!this.isShown) {
+ this.$element.off('keydown.dismiss.bs.modal')
+ }
+ }
+
+ Modal.prototype.resize = function () {
+ if (this.isShown) {
+ $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
+ } else {
+ $(window).off('resize.bs.modal')
+ }
+ }
+
+ Modal.prototype.hideModal = function () {
+ var that = this
+ this.$element.hide()
+ this.backdrop(function () {
+ that.$body.removeClass('modal-open')
+ that.resetAdjustments()
+ that.resetScrollbar()
+ that.$element.trigger('hidden.bs.modal')
+ })
+ }
+
+ Modal.prototype.removeBackdrop = function () {
+ this.$backdrop && this.$backdrop.remove()
+ this.$backdrop = null
+ }
+
+ Modal.prototype.backdrop = function (callback) {
+ var that = this
+ var animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+ if (this.isShown && this.options.backdrop) {
+ var doAnimate = $.support.transition && animate
+
+ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
+ .prependTo(this.$element)
+ .on('click.dismiss.bs.modal', $.proxy(function (e) {
+ if (e.target !== e.currentTarget) return
+ this.options.backdrop == 'static'
+ ? this.$element[0].focus.call(this.$element[0])
+ : this.hide.call(this)
+ }, this))
+
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+ this.$backdrop.addClass('in')
+
+ if (!callback) return
+
+ doAnimate ?
+ this.$backdrop
+ .one('bsTransitionEnd', callback)
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
+ callback()
+
+ } else if (!this.isShown && this.$backdrop) {
+ this.$backdrop.removeClass('in')
+
+ var callbackRemove = function () {
+ that.removeBackdrop()
+ callback && callback()
+ }
+ $.support.transition && this.$element.hasClass('fade') ?
+ this.$backdrop
+ .one('bsTransitionEnd', callbackRemove)
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
+ callbackRemove()
+
+ } else if (callback) {
+ callback()
+ }
+ }
+
+ // these following methods are used to handle overflowing modals
+
+ Modal.prototype.handleUpdate = function () {
+ if (this.options.backdrop) this.adjustBackdrop()
+ this.adjustDialog()
+ }
+
+ Modal.prototype.adjustBackdrop = function () {
+ this.$backdrop
+ .css('height', 0)
+ .css('height', this.$element[0].scrollHeight)
+ }
+
+ Modal.prototype.adjustDialog = function () {
+ var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
+
+ this.$element.css({
+ paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
+ paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
+ })
+ }
+
+ Modal.prototype.resetAdjustments = function () {
+ this.$element.css({
+ paddingLeft: '',
+ paddingRight: ''
+ })
+ }
+
+ Modal.prototype.checkScrollbar = function () {
+ this.bodyIsOverflowing = document.body.scrollHeight > document.documentElement.clientHeight
+ this.scrollbarWidth = this.measureScrollbar()
+ }
+
+ Modal.prototype.setScrollbar = function () {
+ var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
+ if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
+ }
+
+ Modal.prototype.resetScrollbar = function () {
+ this.$body.css('padding-right', '')
+ }
+
+ Modal.prototype.measureScrollbar = function () { // thx walsh
+ var scrollDiv = document.createElement('div')
+ scrollDiv.className = 'modal-scrollbar-measure'
+ this.$body.append(scrollDiv)
+ var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
+ this.$body[0].removeChild(scrollDiv)
+ return scrollbarWidth
+ }
+
+
+ // MODAL PLUGIN DEFINITION
+ // =======================
+
+ function Plugin(option, _relatedTarget) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.modal')
+ var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+ if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
+ if (typeof option == 'string') data[option](_relatedTarget)
+ else if (options.show) data.show(_relatedTarget)
+ })
+ }
+
+ var old = $.fn.modal
+
+ $.fn.modal = Plugin
+ $.fn.modal.Constructor = Modal
+
+
+ // MODAL NO CONFLICT
+ // =================
+
+ $.fn.modal.noConflict = function () {
+ $.fn.modal = old
+ return this
+ }
+
+
+ // MODAL DATA-API
+ // ==============
+
+ $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
+ var $this = $(this)
+ var href = $this.attr('href')
+ var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
+ var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
+
+ if ($this.is('a')) e.preventDefault()
+
+ $target.one('show.bs.modal', function (showEvent) {
+ if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
+ $target.one('hidden.bs.modal', function () {
+ $this.is(':visible') && $this.trigger('focus')
+ })
+ })
+ Plugin.call($target, option, this)
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.3.1
+ * http://getbootstrap.com/javascript/#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // TOOLTIP PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Tooltip = function (element, options) {
+ this.type =
+ this.options =
+ this.enabled =
+ this.timeout =
+ this.hoverState =
+ this.$element = null
+
+ this.init('tooltip', element, options)
+ }
+
+ Tooltip.VERSION = '3.3.1'
+
+ Tooltip.TRANSITION_DURATION = 150
+
+ Tooltip.DEFAULTS = {
+ animation: true,
+ placement: 'top',
+ selector: false,
+ template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
+ trigger: 'hover focus',
+ title: '',
+ delay: 0,
+ html: false,
+ container: false,
+ viewport: {
+ selector: 'body',
+ padding: 0
+ }
+ }
+
+ Tooltip.prototype.init = function (type, element, options) {
+ this.enabled = true
+ this.type = type
+ this.$element = $(element)
+ this.options = this.getOptions(options)
+ this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
+
+ var triggers = this.options.trigger.split(' ')
+
+ for (var i = triggers.length; i--;) {
+ var trigger = triggers[i]
+
+ if (trigger == 'click') {
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+ } else if (trigger != 'manual') {
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
+
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+ }
+ }
+
+ this.options.selector ?
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+ this.fixTitle()
+ }
+
+ Tooltip.prototype.getDefaults = function () {
+ return Tooltip.DEFAULTS
+ }
+
+ Tooltip.prototype.getOptions = function (options) {
+ options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+ if (options.delay && typeof options.delay == 'number') {
+ options.delay = {
+ show: options.delay,
+ hide: options.delay
+ }
+ }
+
+ return options
+ }
+
+ Tooltip.prototype.getDelegateOptions = function () {
+ var options = {}
+ var defaults = this.getDefaults()
+
+ this._options && $.each(this._options, function (key, value) {
+ if (defaults[key] != value) options[key] = value
+ })
+
+ return options
+ }
+
+ Tooltip.prototype.enter = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget).data('bs.' + this.type)
+
+ if (self && self.$tip && self.$tip.is(':visible')) {
+ self.hoverState = 'in'
+ return
+ }
+
+ if (!self) {
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+ $(obj.currentTarget).data('bs.' + this.type, self)
+ }
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'in'
+
+ if (!self.options.delay || !self.options.delay.show) return self.show()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'in') self.show()
+ }, self.options.delay.show)
+ }
+
+ Tooltip.prototype.leave = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget).data('bs.' + this.type)
+
+ if (!self) {
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+ $(obj.currentTarget).data('bs.' + this.type, self)
+ }
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'out'
+
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'out') self.hide()
+ }, self.options.delay.hide)
+ }
+
+ Tooltip.prototype.show = function () {
+ var e = $.Event('show.bs.' + this.type)
+
+ if (this.hasContent() && this.enabled) {
+ this.$element.trigger(e)
+
+ var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
+ if (e.isDefaultPrevented() || !inDom) return
+ var that = this
+
+ var $tip = this.tip()
+
+ var tipId = this.getUID(this.type)
+
+ this.setContent()
+ $tip.attr('id', tipId)
+ this.$element.attr('aria-describedby', tipId)
+
+ if (this.options.animation) $tip.addClass('fade')
+
+ var placement = typeof this.options.placement == 'function' ?
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
+ this.options.placement
+
+ var autoToken = /\s?auto?\s?/i
+ var autoPlace = autoToken.test(placement)
+ if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+ $tip
+ .detach()
+ .css({ top: 0, left: 0, display: 'block' })
+ .addClass(placement)
+ .data('bs.' + this.type, this)
+
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+
+ var pos = this.getPosition()
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (autoPlace) {
+ var orgPlacement = placement
+ var $container = this.options.container ? $(this.options.container) : this.$element.parent()
+ var containerDim = this.getPosition($container)
+
+ placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' :
+ placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' :
+ placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' :
+ placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' :
+ placement
+
+ $tip
+ .removeClass(orgPlacement)
+ .addClass(placement)
+ }
+
+ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+ this.applyPlacement(calculatedOffset, placement)
+
+ var complete = function () {
+ var prevHoverState = that.hoverState
+ that.$element.trigger('shown.bs.' + that.type)
+ that.hoverState = null
+
+ if (prevHoverState == 'out') that.leave(that)
+ }
+
+ $.support.transition && this.$tip.hasClass('fade') ?
+ $tip
+ .one('bsTransitionEnd', complete)
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
+ complete()
+ }
+ }
+
+ Tooltip.prototype.applyPlacement = function (offset, placement) {
+ var $tip = this.tip()
+ var width = $tip[0].offsetWidth
+ var height = $tip[0].offsetHeight
+
+ // manually read margins because getBoundingClientRect includes difference
+ var marginTop = parseInt($tip.css('margin-top'), 10)
+ var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+ // we must check for NaN for ie 8/9
+ if (isNaN(marginTop)) marginTop = 0
+ if (isNaN(marginLeft)) marginLeft = 0
+
+ offset.top = offset.top + marginTop
+ offset.left = offset.left + marginLeft
+
+ // $.fn.offset doesn't round pixel values
+ // so we use setOffset directly with our own function B-0
+ $.offset.setOffset($tip[0], $.extend({
+ using: function (props) {
+ $tip.css({
+ top: Math.round(props.top),
+ left: Math.round(props.left)
+ })
+ }
+ }, offset), 0)
+
+ $tip.addClass('in')
+
+ // check to see if placing tip in new offset caused the tip to resize itself
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (placement == 'top' && actualHeight != height) {
+ offset.top = offset.top + height - actualHeight
+ }
+
+ var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
+
+ if (delta.left) offset.left += delta.left
+ else offset.top += delta.top
+
+ var isVertical = /top|bottom/.test(placement)
+ var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
+ var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
+
+ $tip.offset(offset)
+ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
+ }
+
+ Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) {
+ this.arrow()
+ .css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
+ .css(isHorizontal ? 'top' : 'left', '')
+ }
+
+ Tooltip.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+ $tip.removeClass('fade in top bottom left right')
+ }
+
+ Tooltip.prototype.hide = function (callback) {
+ var that = this
+ var $tip = this.tip()
+ var e = $.Event('hide.bs.' + this.type)
+
+ function complete() {
+ if (that.hoverState != 'in') $tip.detach()
+ that.$element
+ .removeAttr('aria-describedby')
+ .trigger('hidden.bs.' + that.type)
+ callback && callback()
+ }
+
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ $tip.removeClass('in')
+
+ $.support.transition && this.$tip.hasClass('fade') ?
+ $tip
+ .one('bsTransitionEnd', complete)
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
+ complete()
+
+ this.hoverState = null
+
+ return this
+ }
+
+ Tooltip.prototype.fixTitle = function () {
+ var $e = this.$element
+ if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+ }
+ }
+
+ Tooltip.prototype.hasContent = function () {
+ return this.getTitle()
+ }
+
+ Tooltip.prototype.getPosition = function ($element) {
+ $element = $element || this.$element
+
+ var el = $element[0]
+ var isBody = el.tagName == 'BODY'
+
+ var elRect = el.getBoundingClientRect()
+ if (elRect.width == null) {
+ // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
+ elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
+ }
+ var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
+ var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
+ var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
+
+ return $.extend({}, elRect, scroll, outerDims, elOffset)
+ }
+
+ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
+
+ }
+
+ Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
+ var delta = { top: 0, left: 0 }
+ if (!this.$viewport) return delta
+
+ var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
+ var viewportDimensions = this.getPosition(this.$viewport)
+
+ if (/right|left/.test(placement)) {
+ var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
+ var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
+ if (topEdgeOffset < viewportDimensions.top) { // top overflow
+ delta.top = viewportDimensions.top - topEdgeOffset
+ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
+ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
+ }
+ } else {
+ var leftEdgeOffset = pos.left - viewportPadding
+ var rightEdgeOffset = pos.left + viewportPadding + actualWidth
+ if (leftEdgeOffset < viewportDimensions.left) { // left overflow
+ delta.left = viewportDimensions.left - leftEdgeOffset
+ } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
+ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
+ }
+ }
+
+ return delta
+ }
+
+ Tooltip.prototype.getTitle = function () {
+ var title
+ var $e = this.$element
+ var o = this.options
+
+ title = $e.attr('data-original-title')
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
+
+ return title
+ }
+
+ Tooltip.prototype.getUID = function (prefix) {
+ do prefix += ~~(Math.random() * 1000000)
+ while (document.getElementById(prefix))
+ return prefix
+ }
+
+ Tooltip.prototype.tip = function () {
+ return (this.$tip = this.$tip || $(this.options.template))
+ }
+
+ Tooltip.prototype.arrow = function () {
+ return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
+ }
+
+ Tooltip.prototype.enable = function () {
+ this.enabled = true
+ }
+
+ Tooltip.prototype.disable = function () {
+ this.enabled = false
+ }
+
+ Tooltip.prototype.toggleEnabled = function () {
+ this.enabled = !this.enabled
+ }
+
+ Tooltip.prototype.toggle = function (e) {
+ var self = this
+ if (e) {
+ self = $(e.currentTarget).data('bs.' + this.type)
+ if (!self) {
+ self = new this.constructor(e.currentTarget, this.getDelegateOptions())
+ $(e.currentTarget).data('bs.' + this.type, self)
+ }
+ }
+
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+ }
+
+ Tooltip.prototype.destroy = function () {
+ var that = this
+ clearTimeout(this.timeout)
+ this.hide(function () {
+ that.$element.off('.' + that.type).removeData('bs.' + that.type)
+ })
+ }
+
+
+ // TOOLTIP PLUGIN DEFINITION
+ // =========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tooltip')
+ var options = typeof option == 'object' && option
+ var selector = options && options.selector
+
+ if (!data && option == 'destroy') return
+ if (selector) {
+ if (!data) $this.data('bs.tooltip', (data = {}))
+ if (!data[selector]) data[selector] = new Tooltip(this, options)
+ } else {
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+ }
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.tooltip
+
+ $.fn.tooltip = Plugin
+ $.fn.tooltip.Constructor = Tooltip
+
+
+ // TOOLTIP NO CONFLICT
+ // ===================
+
+ $.fn.tooltip.noConflict = function () {
+ $.fn.tooltip = old
+ return this
+ }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: popover.js v3.3.1
+ * http://getbootstrap.com/javascript/#popovers
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // POPOVER PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Popover = function (element, options) {
+ this.init('popover', element, options)
+ }
+
+ if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+ Popover.VERSION = '3.3.1'
+
+ Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
+ placement: 'right',
+ trigger: 'click',
+ content: '',
+ template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+ })
+
+
+ // NOTE: POPOVER EXTENDS tooltip.js
+ // ================================
+
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+ Popover.prototype.constructor = Popover
+
+ Popover.prototype.getDefaults = function () {
+ return Popover.DEFAULTS
+ }
+
+ Popover.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+ var content = this.getContent()
+
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+ $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
+ this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+ ](content)
+
+ $tip.removeClass('fade top bottom left right in')
+
+ // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+ // this manually by checking the contents.
+ if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+ }
+
+ Popover.prototype.hasContent = function () {
+ return this.getTitle() || this.getContent()
+ }
+
+ Popover.prototype.getContent = function () {
+ var $e = this.$element
+ var o = this.options
+
+ return $e.attr('data-content')
+ || (typeof o.content == 'function' ?
+ o.content.call($e[0]) :
+ o.content)
+ }
+
+ Popover.prototype.arrow = function () {
+ return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
+ }
+
+ Popover.prototype.tip = function () {
+ if (!this.$tip) this.$tip = $(this.options.template)
+ return this.$tip
+ }
+
+
+ // POPOVER PLUGIN DEFINITION
+ // =========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.popover')
+ var options = typeof option == 'object' && option
+ var selector = options && options.selector
+
+ if (!data && option == 'destroy') return
+ if (selector) {
+ if (!data) $this.data('bs.popover', (data = {}))
+ if (!data[selector]) data[selector] = new Popover(this, options)
+ } else {
+ if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+ }
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.popover
+
+ $.fn.popover = Plugin
+ $.fn.popover.Constructor = Popover
+
+
+ // POPOVER NO CONFLICT
+ // ===================
+
+ $.fn.popover.noConflict = function () {
+ $.fn.popover = old
+ return this
+ }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: scrollspy.js v3.3.1
+ * http://getbootstrap.com/javascript/#scrollspy
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // SCROLLSPY CLASS DEFINITION
+ // ==========================
+
+ function ScrollSpy(element, options) {
+ var process = $.proxy(this.process, this)
+
+ this.$body = $('body')
+ this.$scrollElement = $(element).is('body') ? $(window) : $(element)
+ this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
+ this.selector = (this.options.target || '') + ' .nav li > a'
+ this.offsets = []
+ this.targets = []
+ this.activeTarget = null
+ this.scrollHeight = 0
+
+ this.$scrollElement.on('scroll.bs.scrollspy', process)
+ this.refresh()
+ this.process()
+ }
+
+ ScrollSpy.VERSION = '3.3.1'
+
+ ScrollSpy.DEFAULTS = {
+ offset: 10
+ }
+
+ ScrollSpy.prototype.getScrollHeight = function () {
+ return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
+ }
+
+ ScrollSpy.prototype.refresh = function () {
+ var offsetMethod = 'offset'
+ var offsetBase = 0
+
+ if (!$.isWindow(this.$scrollElement[0])) {
+ offsetMethod = 'position'
+ offsetBase = this.$scrollElement.scrollTop()
+ }
+
+ this.offsets = []
+ this.targets = []
+ this.scrollHeight = this.getScrollHeight()
+
+ var self = this
+
+ this.$body
+ .find(this.selector)
+ .map(function () {
+ var $el = $(this)
+ var href = $el.data('target') || $el.attr('href')
+ var $href = /^#./.test(href) && $(href)
+
+ return ($href
+ && $href.length
+ && $href.is(':visible')
+ && [[$href[offsetMethod]().top + offsetBase, href]]) || null
+ })
+ .sort(function (a, b) { return a[0] - b[0] })
+ .each(function () {
+ self.offsets.push(this[0])
+ self.targets.push(this[1])
+ })
+ }
+
+ ScrollSpy.prototype.process = function () {
+ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
+ var scrollHeight = this.getScrollHeight()
+ var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
+ var offsets = this.offsets
+ var targets = this.targets
+ var activeTarget = this.activeTarget
+ var i
+
+ if (this.scrollHeight != scrollHeight) {
+ this.refresh()
+ }
+
+ if (scrollTop >= maxScroll) {
+ return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
+ }
+
+ if (activeTarget && scrollTop < offsets[0]) {
+ this.activeTarget = null
+ return this.clear()
+ }
+
+ for (i = offsets.length; i--;) {
+ activeTarget != targets[i]
+ && scrollTop >= offsets[i]
+ && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
+ && this.activate(targets[i])
+ }
+ }
+
+ ScrollSpy.prototype.activate = function (target) {
+ this.activeTarget = target
+
+ this.clear()
+
+ var selector = this.selector +
+ '[data-target="' + target + '"],' +
+ this.selector + '[href="' + target + '"]'
+
+ var active = $(selector)
+ .parents('li')
+ .addClass('active')
+
+ if (active.parent('.dropdown-menu').length) {
+ active = active
+ .closest('li.dropdown')
+ .addClass('active')
+ }
+
+ active.trigger('activate.bs.scrollspy')
+ }
+
+ ScrollSpy.prototype.clear = function () {
+ $(this.selector)
+ .parentsUntil(this.options.target, '.active')
+ .removeClass('active')
+ }
+
+
+ // SCROLLSPY PLUGIN DEFINITION
+ // ===========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.scrollspy')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.scrollspy
+
+ $.fn.scrollspy = Plugin
+ $.fn.scrollspy.Constructor = ScrollSpy
+
+
+ // SCROLLSPY NO CONFLICT
+ // =====================
+
+ $.fn.scrollspy.noConflict = function () {
+ $.fn.scrollspy = old
+ return this
+ }
+
+
+ // SCROLLSPY DATA-API
+ // ==================
+
+ $(window).on('load.bs.scrollspy.data-api', function () {
+ $('[data-spy="scroll"]').each(function () {
+ var $spy = $(this)
+ Plugin.call($spy, $spy.data())
+ })
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tab.js v3.3.1
+ * http://getbootstrap.com/javascript/#tabs
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // TAB CLASS DEFINITION
+ // ====================
+
+ var Tab = function (element) {
+ this.element = $(element)
+ }
+
+ Tab.VERSION = '3.3.1'
+
+ Tab.TRANSITION_DURATION = 150
+
+ Tab.prototype.show = function () {
+ var $this = this.element
+ var $ul = $this.closest('ul:not(.dropdown-menu)')
+ var selector = $this.data('target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+ }
+
+ if ($this.parent('li').hasClass('active')) return
+
+ var $previous = $ul.find('.active:last a')
+ var hideEvent = $.Event('hide.bs.tab', {
+ relatedTarget: $this[0]
+ })
+ var showEvent = $.Event('show.bs.tab', {
+ relatedTarget: $previous[0]
+ })
+
+ $previous.trigger(hideEvent)
+ $this.trigger(showEvent)
+
+ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
+
+ var $target = $(selector)
+
+ this.activate($this.closest('li'), $ul)
+ this.activate($target, $target.parent(), function () {
+ $previous.trigger({
+ type: 'hidden.bs.tab',
+ relatedTarget: $this[0]
+ })
+ $this.trigger({
+ type: 'shown.bs.tab',
+ relatedTarget: $previous[0]
+ })
+ })
+ }
+
+ Tab.prototype.activate = function (element, container, callback) {
+ var $active = container.find('> .active')
+ var transition = callback
+ && $.support.transition
+ && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)
+
+ function next() {
+ $active
+ .removeClass('active')
+ .find('> .dropdown-menu > .active')
+ .removeClass('active')
+ .end()
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', false)
+
+ element
+ .addClass('active')
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', true)
+
+ if (transition) {
+ element[0].offsetWidth // reflow for transition
+ element.addClass('in')
+ } else {
+ element.removeClass('fade')
+ }
+
+ if (element.parent('.dropdown-menu')) {
+ element
+ .closest('li.dropdown')
+ .addClass('active')
+ .end()
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', true)
+ }
+
+ callback && callback()
+ }
+
+ $active.length && transition ?
+ $active
+ .one('bsTransitionEnd', next)
+ .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
+ next()
+
+ $active.removeClass('in')
+ }
+
+
+ // TAB PLUGIN DEFINITION
+ // =====================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tab')
+
+ if (!data) $this.data('bs.tab', (data = new Tab(this)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.tab
+
+ $.fn.tab = Plugin
+ $.fn.tab.Constructor = Tab
+
+
+ // TAB NO CONFLICT
+ // ===============
+
+ $.fn.tab.noConflict = function () {
+ $.fn.tab = old
+ return this
+ }
+
+
+ // TAB DATA-API
+ // ============
+
+ var clickHandler = function (e) {
+ e.preventDefault()
+ Plugin.call($(this), 'show')
+ }
+
+ $(document)
+ .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
+ .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: affix.js v3.3.1
+ * http://getbootstrap.com/javascript/#affix
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // AFFIX CLASS DEFINITION
+ // ======================
+
+ var Affix = function (element, options) {
+ this.options = $.extend({}, Affix.DEFAULTS, options)
+
+ this.$target = $(this.options.target)
+ .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
+ .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
+
+ this.$element = $(element)
+ this.affixed =
+ this.unpin =
+ this.pinnedOffset = null
+
+ this.checkPosition()
+ }
+
+ Affix.VERSION = '3.3.1'
+
+ Affix.RESET = 'affix affix-top affix-bottom'
+
+ Affix.DEFAULTS = {
+ offset: 0,
+ target: window
+ }
+
+ Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
+ var scrollTop = this.$target.scrollTop()
+ var position = this.$element.offset()
+ var targetHeight = this.$target.height()
+
+ if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
+
+ if (this.affixed == 'bottom') {
+ if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
+ return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
+ }
+
+ var initializing = this.affixed == null
+ var colliderTop = initializing ? scrollTop : position.top
+ var colliderHeight = initializing ? targetHeight : height
+
+ if (offsetTop != null && colliderTop <= offsetTop) return 'top'
+ if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
+
+ return false
+ }
+
+ Affix.prototype.getPinnedOffset = function () {
+ if (this.pinnedOffset) return this.pinnedOffset
+ this.$element.removeClass(Affix.RESET).addClass('affix')
+ var scrollTop = this.$target.scrollTop()
+ var position = this.$element.offset()
+ return (this.pinnedOffset = position.top - scrollTop)
+ }
+
+ Affix.prototype.checkPositionWithEventLoop = function () {
+ setTimeout($.proxy(this.checkPosition, this), 1)
+ }
+
+ Affix.prototype.checkPosition = function () {
+ if (!this.$element.is(':visible')) return
+
+ var height = this.$element.height()
+ var offset = this.options.offset
+ var offsetTop = offset.top
+ var offsetBottom = offset.bottom
+ var scrollHeight = $('body').height()
+
+ if (typeof offset != 'object') offsetBottom = offsetTop = offset
+ if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
+ if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
+
+ var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
+
+ if (this.affixed != affix) {
+ if (this.unpin != null) this.$element.css('top', '')
+
+ var affixType = 'affix' + (affix ? '-' + affix : '')
+ var e = $.Event(affixType + '.bs.affix')
+
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ this.affixed = affix
+ this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
+
+ this.$element
+ .removeClass(Affix.RESET)
+ .addClass(affixType)
+ .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
+ }
+
+ if (affix == 'bottom') {
+ this.$element.offset({
+ top: scrollHeight - height - offsetBottom
+ })
+ }
+ }
+
+
+ // AFFIX PLUGIN DEFINITION
+ // =======================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.affix')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.affix
+
+ $.fn.affix = Plugin
+ $.fn.affix.Constructor = Affix
+
+
+ // AFFIX NO CONFLICT
+ // =================
+
+ $.fn.affix.noConflict = function () {
+ $.fn.affix = old
+ return this
+ }
+
+
+ // AFFIX DATA-API
+ // ==============
+
+ $(window).on('load', function () {
+ $('[data-spy="affix"]').each(function () {
+ var $spy = $(this)
+ var data = $spy.data()
+
+ data.offset = data.offset || {}
+
+ if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
+ if (data.offsetTop != null) data.offset.top = data.offsetTop
+
+ Plugin.call($spy, data)
+ })
+ })
+
+}(jQuery);
diff --git a/libccnx-common/documentation/doxygen-extras/bootstrap/js/bootstrap.min.js b/libccnx-common/documentation/doxygen-extras/bootstrap/js/bootstrap.min.js
new file mode 100644
index 00000000..d8398659
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/bootstrap/js/bootstrap.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.1",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.1",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.1",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c="prev"==a?-1:1,d=this.getItemIndex(b),e=(d+c)%this.$items.length;return this.$items.eq(e)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i="next"==b?"first":"last",j=this;if(!f.length){if(!this.options.wrap)return;f=this.$element.find(".item")[i]()}if(f.hasClass("active"))return this.sliding=!1;var k=f[0],l=a.Event("slide.bs.carousel",{relatedTarget:k,direction:h});if(this.$element.trigger(l),!l.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var m=a(this.$indicators.children()[this.getItemIndex(f)]);m&&m.addClass("active")}var n=a.Event("slid.bs.carousel",{relatedTarget:k,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),j.sliding=!1,setTimeout(function(){j.$element.trigger(n)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(n)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a(this.options.trigger).filter('[href="#'+b.id+'"], [data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.1",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0,trigger:'[data-toggle="collapse"]'},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.find("> .panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":a.extend({},e.data(),{trigger:this});c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.1",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(b){if(/(38|40|27|32)/.test(b.which)&&!/input|textarea/i.test(b.target.tagName)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var e=c(d),g=e.hasClass("open");if(!g&&27!=b.which||g&&27==b.which)return 27==b.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.divider):visible a",i=e.find('[role="menu"]'+h+', [role="listbox"]'+h);if(i.length){var j=i.index(b.target);38==b.which&&j>0&&j--,40==b.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",'[role="menu"]',g.prototype.keydown).on("keydown.bs.dropdown.data-api",'[role="listbox"]',g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$backdrop=this.isShown=null,this.scrollbarWidth=0,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.1",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.options.backdrop&&d.adjustBackdrop(),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in").attr("aria-hidden",!1),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$element.find(".modal-dialog").one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a('<div class="modal-backdrop '+e+'" />').prependTo(this.$element).on("click.dismiss.bs.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.options.backdrop&&this.adjustBackdrop(),this.adjustDialog()},c.prototype.adjustBackdrop=function(){this.$backdrop.css("height",0).css("height",this.$element[0].scrollHeight)},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){this.bodyIsOverflowing=document.body.scrollHeight>document.documentElement.clientHeight,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right","")},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b,g=f&&f.selector;(e||"destroy"!=b)&&(g?(e||d.data("bs.tooltip",e={}),e[g]||(e[g]=new c(this,f))):e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};c.VERSION="3.3.1",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c&&c.$tip&&c.$tip.is(":visible")?void(c.hoverState="in"):(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.options.container?a(this.options.container):this.$element.parent(),p=this.getPosition(o);h="bottom"==h&&k.bottom+m>p.bottom?"top":"top"==h&&k.top-m<p.top?"bottom":"right"==h&&k.right+l>p.width?"left":"left"==h&&k.left-l<p.left?"right":h,f.removeClass(n).addClass(h)}var q=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(q,h);var r=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",r).emulateTransitionEnd(c.TRANSITION_DURATION):r()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top=b.top+g,b.left=b.left+h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=this.tip(),g=a.Event("hide.bs."+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type)})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b,g=f&&f.selector;(e||"destroy"!=b)&&(g?(e||d.data("bs.popover",e={}),e[g]||(e[g]=new c(this,f))):e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.1",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},c.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){var e=a.proxy(this.process,this);this.$body=a("body"),this.$scrollElement=a(a(c).is("body")?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",e),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.1",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b="offset",c=0;a.isWindow(this.$scrollElement[0])||(b="position",c=this.$scrollElement.scrollTop()),this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight();var d=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[b]().top+c,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){d.offsets.push(this[0]),d.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.1",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})
+})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=this.unpin=this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.1",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=i?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=a("body").height();"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file
diff --git a/libccnx-common/documentation/doxygen-extras/bootstrap/js/npm.js b/libccnx-common/documentation/doxygen-extras/bootstrap/js/npm.js
new file mode 100644
index 00000000..bf6aa806
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/bootstrap/js/npm.js
@@ -0,0 +1,13 @@
+// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
+require('../../js/transition.js')
+require('../../js/alert.js')
+require('../../js/button.js')
+require('../../js/carousel.js')
+require('../../js/collapse.js')
+require('../../js/dropdown.js')
+require('../../js/modal.js')
+require('../../js/tooltip.js')
+require('../../js/popover.js')
+require('../../js/scrollspy.js')
+require('../../js/tab.js')
+require('../../js/affix.js') \ No newline at end of file
diff --git a/libccnx-common/documentation/doxygen-extras/customdoxygen.css b/libccnx-common/documentation/doxygen-extras/customdoxygen.css
new file mode 100644
index 00000000..8560f848
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/customdoxygen.css
@@ -0,0 +1,1705 @@
+/* The standard CSS for doxygen 1.8.9.1 */
+
+body, table, div, p, dl {
+ font: 400 14px/22px Helvetica,sans-serif;
+}
+
+/* @group Heading Levels */
+
+h1.groupheader {
+ font-size: 150%;
+}
+
+.title {
+ font: 400 14px/28px Roboto,sans-serif;
+ font-size: 150%;
+ font-weight: bold;
+ margin: 10px 2px;
+}
+
+h2.groupheader {
+ border-bottom: 1px solid #879ECB;
+ color: #354C7B;
+ font-size: 150%;
+ font-weight: normal;
+ margin-top: 1.75em;
+ padding-top: 8px;
+ padding-bottom: 4px;
+ width: 100%;
+}
+
+h3.groupheader {
+ font-size: 100%;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ -webkit-transition: text-shadow 0.5s linear;
+ -moz-transition: text-shadow 0.5s linear;
+ -ms-transition: text-shadow 0.5s linear;
+ -o-transition: text-shadow 0.5s linear;
+ transition: text-shadow 0.5s linear;
+ margin-right: 15px;
+}
+
+h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow {
+ text-shadow: 0 0 15px cyan;
+}
+
+dt {
+ font-weight: bold;
+}
+
+div.multicol {
+ -moz-column-gap: 1em;
+ -webkit-column-gap: 1em;
+ -moz-column-count: 3;
+ -webkit-column-count: 3;
+}
+
+p.startli, p.startdd {
+ margin-top: 2px;
+}
+
+p.starttd {
+ margin-top: 0px;
+}
+
+p.endli {
+ margin-bottom: 0px;
+}
+
+p.enddd {
+ margin-bottom: 4px;
+}
+
+p.endtd {
+ margin-bottom: 2px;
+}
+
+/* @end */
+
+caption {
+ font-weight: bold;
+}
+
+span.legend {
+ font-size: 70%;
+ text-align: center;
+}
+
+h3.version {
+ font-size: 90%;
+ text-align: center;
+}
+
+div.qindex, div.navtab{
+ background-color: #EBEFF6;
+ border: 1px solid #A3B4D7;
+ text-align: center;
+}
+
+div.qindex, div.navpath {
+ width: 100%;
+ line-height: 140%;
+}
+
+div.navtab {
+ margin-right: 15px;
+}
+
+/* @group Link Styling */
+
+a {
+ color: #3D578C;
+ font-weight: normal;
+ text-decoration: none;
+}
+
+.contents a:visited {
+ color: #4665A2;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+a.qindex {
+ font-weight: bold;
+}
+
+a.qindexHL {
+ font-weight: bold;
+ background-color: #9CAFD4;
+ color: #ffffff;
+ border: 1px double #869DCA;
+}
+
+.contents a.qindexHL:visited {
+ color: #ffffff;
+}
+
+a.el {
+ font-weight: bold;
+}
+
+a.elRef {
+}
+
+a.code, a.code:visited, a.line, a.line:visited {
+ color: #4665A2;
+}
+
+a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
+ color: #4665A2;
+}
+
+/* @end */
+
+dl.el {
+ margin-left: -1cm;
+}
+
+pre.fragment {
+ border: 1px solid #C4CFE5;
+ background-color: #FBFCFD;
+ padding: 4px 6px;
+ margin: 4px 8px 4px 2px;
+ overflow: auto;
+ word-wrap: break-word;
+ font-size: 9pt;
+ line-height: 125%;
+ font-family: monospace, fixed;
+ font-size: 105%;
+}
+
+div.fragment {
+ padding: 4px 6px;
+ margin: 4px 8px 4px 2px;
+ background-color: #FBFCFD;
+ border: 1px solid #C4CFE5;
+}
+
+div.line {
+ font-family: monospace, fixed;
+ font-size: 13px;
+ min-height: 13px;
+ line-height: 1.0;
+ text-wrap: unrestricted;
+ white-space: -moz-pre-wrap; /* Moz */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: pre-wrap; /* CSS3 */
+ word-wrap: break-word; /* IE 5.5+ */
+ text-indent: -53px;
+ padding-left: 53px;
+ padding-bottom: 0px;
+ margin: 0px;
+ -webkit-transition-property: background-color, box-shadow;
+ -webkit-transition-duration: 0.5s;
+ -moz-transition-property: background-color, box-shadow;
+ -moz-transition-duration: 0.5s;
+ -ms-transition-property: background-color, box-shadow;
+ -ms-transition-duration: 0.5s;
+ -o-transition-property: background-color, box-shadow;
+ -o-transition-duration: 0.5s;
+ transition-property: background-color, box-shadow;
+ transition-duration: 0.5s;
+}
+
+div.line.glow {
+ background-color: cyan;
+ box-shadow: 0 0 10px cyan;
+}
+
+
+span.lineno {
+ padding-right: 4px;
+ text-align: right;
+ border-right: 2px solid #0F0;
+ background-color: #E8E8E8;
+ white-space: pre;
+}
+span.lineno a {
+ background-color: #D8D8D8;
+}
+
+span.lineno a:hover {
+ background-color: #C8C8C8;
+}
+
+div.ah, span.ah {
+ background-color: black;
+ font-weight: bold;
+ color: #ffffff;
+ margin-bottom: 3px;
+ margin-top: 3px;
+ padding: 0.2em;
+ border: solid thin #333;
+ border-radius: 0.5em;
+ -webkit-border-radius: .5em;
+ -moz-border-radius: .5em;
+ box-shadow: 2px 2px 3px #999;
+ -webkit-box-shadow: 2px 2px 3px #999;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
+ background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
+}
+
+div.classindex ul {
+ list-style: none;
+ padding-left: 0;
+}
+
+div.classindex span.ai {
+ display: inline-block;
+}
+
+div.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ font-weight: bold;
+}
+
+div.groupText {
+ margin-left: 16px;
+ font-style: italic;
+}
+
+body {
+ background-color: white;
+ color: black;
+ margin: 0;
+}
+
+div.contents {
+ margin-top: 10px;
+ margin-left: 12px;
+ margin-right: 8px;
+}
+
+td.indexkey {
+ background-color: #EBEFF6;
+ font-weight: bold;
+ border: 1px solid #C4CFE5;
+ margin: 2px 0px 2px 0;
+ padding: 2px 10px;
+ white-space: nowrap;
+ vertical-align: top;
+}
+
+td.indexvalue {
+ background-color: #EBEFF6;
+ border: 1px solid #C4CFE5;
+ padding: 2px 10px;
+ margin: 2px 0px;
+}
+
+tr.memlist {
+ background-color: #EEF1F7;
+}
+
+p.formulaDsp {
+ text-align: center;
+}
+
+img.formulaDsp {
+
+}
+
+img.formulaInl {
+ vertical-align: middle;
+}
+
+div.center {
+ text-align: center;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0px;
+}
+
+div.center img {
+ border: 0px;
+}
+
+address.footer {
+ text-align: right;
+ padding-right: 12px;
+}
+
+img.footer {
+ border: 0px;
+ vertical-align: middle;
+}
+
+/* @group Code Colorization */
+
+span.keyword {
+ color: #008000
+}
+
+span.keywordtype {
+ color: #604020
+}
+
+span.keywordflow {
+ color: #e08000
+}
+
+span.comment {
+ color: #800000
+}
+
+span.preprocessor {
+ color: #806020
+}
+
+span.stringliteral {
+ color: #002080
+}
+
+span.charliteral {
+ color: #008080
+}
+
+span.vhdldigit {
+ color: #ff00ff
+}
+
+span.vhdlchar {
+ color: #000000
+}
+
+span.vhdlkeyword {
+ color: #700070
+}
+
+span.vhdllogic {
+ color: #ff0000
+}
+
+blockquote {
+ background-color: #F7F8FB;
+ border-left: 2px solid #9CAFD4;
+ margin: 0 24px 0 4px;
+ padding: 0 12px 0 16px;
+}
+
+/* @end */
+
+/*
+.search {
+ color: #003399;
+ font-weight: bold;
+}
+
+form.search {
+ margin-bottom: 0px;
+ margin-top: 0px;
+}
+
+input.search {
+ font-size: 75%;
+ color: #000080;
+ font-weight: normal;
+ background-color: #e8eef2;
+}
+*/
+
+td.tiny {
+ font-size: 75%;
+}
+
+.dirtab {
+ padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #A3B4D7;
+}
+
+th.dirtab {
+ background: #EBEFF6;
+ font-weight: bold;
+}
+
+hr {
+ height: 0px;
+ border: none;
+ border-top: 1px solid #4A6AAA;
+}
+
+hr.footer {
+ height: 1px;
+}
+
+/* @group Member Descriptions */
+
+table.memberdecls {
+ border-spacing: 0px;
+ padding: 0px;
+}
+
+.memberdecls td, .fieldtable tr {
+ -webkit-transition-property: background-color, box-shadow;
+ -webkit-transition-duration: 0.5s;
+ -moz-transition-property: background-color, box-shadow;
+ -moz-transition-duration: 0.5s;
+ -ms-transition-property: background-color, box-shadow;
+ -ms-transition-duration: 0.5s;
+ -o-transition-property: background-color, box-shadow;
+ -o-transition-duration: 0.5s;
+ transition-property: background-color, box-shadow;
+ transition-duration: 0.5s;
+}
+
+.memberdecls td.glow, .fieldtable tr.glow {
+ background-color: cyan;
+ box-shadow: 0 0 15px cyan;
+}
+
+.mdescLeft, .mdescRight,
+.memItemLeft, .memItemRight,
+.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
+ background-color: #F9FAFC;
+ border: none;
+ margin: 4px;
+ padding: 1px 0 0 8px;
+}
+
+.mdescLeft, .mdescRight {
+ padding: 0px 8px 4px 8px;
+ color: #555;
+}
+
+.memSeparator {
+ border-bottom: 1px solid #DEE4F0;
+ line-height: 1px;
+ margin: 0px;
+ padding: 0px;
+}
+
+.memItemLeft, .memTemplItemLeft {
+ white-space: nowrap;
+}
+
+.memItemRight {
+ width: 100%;
+}
+
+.memTemplParams {
+ color: #4665A2;
+ white-space: nowrap;
+ font-size: 80%;
+}
+
+/* @end */
+
+/* @group Member Details */
+
+/* Styles for detailed member documentation */
+
+.memtemplate {
+ font-size: 80%;
+ color: #4665A2;
+ font-weight: normal;
+ margin-left: 9px;
+}
+
+.memnav {
+ background-color: #EBEFF6;
+ border: 1px solid #A3B4D7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+
+.mempage {
+ width: 100%;
+}
+
+.memitem {
+ padding: 0;
+ margin-bottom: 10px;
+ margin-right: 5px;
+ -webkit-transition: box-shadow 0.5s linear;
+ -moz-transition: box-shadow 0.5s linear;
+ -ms-transition: box-shadow 0.5s linear;
+ -o-transition: box-shadow 0.5s linear;
+ transition: box-shadow 0.5s linear;
+ display: table !important;
+ width: 100%;
+}
+
+.memitem.glow {
+ box-shadow: 0 0 15px cyan;
+}
+
+.memname {
+ font-weight: bold;
+ margin-left: 6px;
+}
+
+.memname td {
+ vertical-align: bottom;
+}
+
+.memproto, dl.reflist dt {
+ border-top: 1px solid #A8B8D9;
+ border-left: 1px solid #A8B8D9;
+ border-right: 1px solid #A8B8D9;
+ padding: 6px 0px 6px 0px;
+ color: #253555;
+ font-weight: bold;
+ text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+ background-image:url('nav_f.png');
+ background-repeat:repeat-x;
+ background-color: #E2E8F2;
+ /* opera specific markup */
+ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ /* firefox specific markup */
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+ -moz-border-radius-topright: 4px;
+ -moz-border-radius-topleft: 4px;
+ /* webkit specific markup */
+ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ -webkit-border-top-right-radius: 4px;
+ -webkit-border-top-left-radius: 4px;
+
+}
+
+.memdoc, dl.reflist dd {
+ border-bottom: 1px solid #A8B8D9;
+ border-left: 1px solid #A8B8D9;
+ border-right: 1px solid #A8B8D9;
+ padding: 6px 10px 2px 10px;
+ background-color: #FBFCFD;
+ border-top-width: 0;
+ background-image:url('nav_g.png');
+ background-repeat:repeat-x;
+ background-color: #FFFFFF;
+ /* opera specific markup */
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ /* firefox specific markup */
+ -moz-border-radius-bottomleft: 4px;
+ -moz-border-radius-bottomright: 4px;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+ /* webkit specific markup */
+ -webkit-border-bottom-left-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+}
+
+dl.reflist dt {
+ padding: 5px;
+}
+
+dl.reflist dd {
+ margin: 0px 0px 10px 0px;
+ padding: 5px;
+}
+
+.paramkey {
+ text-align: right;
+}
+
+.paramtype {
+ white-space: nowrap;
+}
+
+.paramname {
+ color: #602020;
+ white-space: nowrap;
+}
+.paramname em {
+ font-style: normal;
+}
+.paramname code {
+ line-height: 14px;
+}
+
+.params, .retval, .exception, .tparams {
+ margin-left: 0px;
+ padding-left: 0px;
+}
+
+.params .paramname, .retval .paramname {
+ font-weight: bold;
+ vertical-align: top;
+}
+
+.params .paramtype {
+ font-style: italic;
+ vertical-align: top;
+}
+
+.params .paramdir {
+ font-family: "courier new",courier,monospace;
+ vertical-align: top;
+}
+
+table.mlabels {
+ border-spacing: 0px;
+}
+
+td.mlabels-left {
+ width: 100%;
+ padding: 0px;
+}
+
+td.mlabels-right {
+ vertical-align: bottom;
+ padding: 0px;
+ white-space: nowrap;
+}
+
+span.mlabels {
+ margin-left: 8px;
+}
+
+span.mlabel {
+ background-color: #205469;
+ border-top:1px solid #5373B4;
+ border-left:1px solid #5373B4;
+ border-right:1px solid #C4CFE5;
+ border-bottom:1px solid #C4CFE5;
+ text-shadow: none;
+ color: white;
+ margin-right: 4px;
+ padding: 2px 3px;
+ border-radius: 3px;
+ font-size: 7pt;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+
+
+
+/* @end */
+
+/* these are for tree view inside a (index) page */
+
+div.directory {
+ margin: 10px 0px;
+ border-top: 1px solid #9CAFD4;
+ border-bottom: 1px solid #9CAFD4;
+ width: 100%;
+}
+
+.directory table {
+ border-collapse:collapse;
+}
+
+.directory td {
+ margin: 0px;
+ padding: 0px;
+ vertical-align: top;
+}
+
+.directory td.entry {
+ white-space: nowrap;
+ padding-right: 6px;
+ padding-top: 3px;
+}
+
+.directory td.entry a {
+ outline:none;
+}
+
+.directory td.entry a img {
+ border: none;
+}
+
+.directory td.desc {
+ width: 100%;
+ padding-left: 6px;
+ padding-right: 6px;
+ padding-top: 3px;
+ border-left: 1px solid rgba(0,0,0,0.05);
+}
+
+.directory tr.even {
+ padding-left: 6px;
+ background-color: #F7F8FB;
+}
+
+.directory img {
+ vertical-align: -30%;
+}
+
+.directory .levels {
+ white-space: nowrap;
+ width: 100%;
+ text-align: right;
+ font-size: 9pt;
+}
+
+.directory .levels span {
+ cursor: pointer;
+ padding-left: 2px;
+ padding-right: 2px;
+ color: #3D578C;
+}
+
+.arrow {
+ color: #9CAFD4;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ cursor: pointer;
+ font-size: 80%;
+ display: inline-block;
+ width: 16px;
+ height: 22px;
+}
+
+.icon {
+ font-family: Arial, Helvetica;
+ font-weight: bold;
+ font-size: 12px;
+ height: 14px;
+ width: 16px;
+ display: inline-block;
+ background-color: #728DC1;
+ color: white;
+ text-align: center;
+ border-radius: 4px;
+ margin-left: 2px;
+ margin-right: 2px;
+}
+
+.icona {
+ width: 24px;
+ height: 22px;
+ display: inline-block;
+}
+
+.iconfopen {
+ width: 24px;
+ height: 18px;
+ margin-bottom: 4px;
+ background-image:url('folderopen.png');
+ background-position: 0px -4px;
+ background-repeat: repeat-y;
+ vertical-align:top;
+ display: inline-block;
+}
+
+.iconfclosed {
+ width: 24px;
+ height: 18px;
+ margin-bottom: 4px;
+ background-image:url('folderclosed.png');
+ background-position: 0px -4px;
+ background-repeat: repeat-y;
+ vertical-align:top;
+ display: inline-block;
+}
+
+.icondoc {
+ width: 24px;
+ height: 18px;
+ margin-bottom: 4px;
+ background-image:url('doc.png');
+ background-position: 0px -4px;
+ background-repeat: repeat-y;
+ vertical-align:top;
+ display: inline-block;
+}
+
+table.directory {
+ font: 400 14px Roboto,sans-serif;
+}
+
+/* @end */
+
+div.dynheader {
+ margin-top: 8px;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+address {
+ font-style: normal;
+ color: #2A3D61;
+}
+
+table.doxtable {
+ border-collapse:collapse;
+ margin-top: 4px;
+ margin-bottom: 4px;
+}
+
+table.doxtable td, table.doxtable th {
+ border: 1px solid #2D4068;
+ padding: 3px 7px 2px;
+}
+
+table.doxtable th {
+ background-color: #374F7F;
+ color: #FFFFFF;
+ font-size: 110%;
+ padding-bottom: 4px;
+ padding-top: 5px;
+}
+
+table.fieldtable {
+ /*width: 100%;*/
+ margin-bottom: 10px;
+ border: 1px solid #A8B8D9;
+ border-spacing: 0px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+ -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
+ box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
+}
+
+.fieldtable td, .fieldtable th {
+ padding: 3px 7px 2px;
+}
+
+.fieldtable td.fieldtype, .fieldtable td.fieldname {
+ white-space: nowrap;
+ border-right: 1px solid #A8B8D9;
+ border-bottom: 1px solid #A8B8D9;
+ vertical-align: top;
+}
+
+.fieldtable td.fieldname {
+ padding-top: 3px;
+}
+
+.fieldtable td.fielddoc {
+ border-bottom: 1px solid #A8B8D9;
+ /*width: 100%;*/
+}
+
+.fieldtable td.fielddoc p:first-child {
+ margin-top: 0px;
+}
+
+.fieldtable td.fielddoc p:last-child {
+ margin-bottom: 2px;
+}
+
+.fieldtable tr:last-child td {
+ border-bottom: none;
+}
+
+.fieldtable th {
+ background-image:url('nav_f.png');
+ background-repeat:repeat-x;
+ background-color: #E2E8F2;
+ font-size: 90%;
+ color: #253555;
+ padding-bottom: 4px;
+ padding-top: 5px;
+ text-align:left;
+ -moz-border-radius-topleft: 4px;
+ -moz-border-radius-topright: 4px;
+ -webkit-border-top-left-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ border-bottom: 1px solid #A8B8D9;
+}
+
+
+.tabsearch {
+ top: 0px;
+ left: 10px;
+ height: 36px;
+ background-image: url('tab_b.png');
+ z-index: 101;
+ overflow: hidden;
+ font-size: 13px;
+}
+
+.navpath ul
+{
+ font-size: 11px;
+ background-image:url('tab_b.png');
+ background-repeat:repeat-x;
+ background-position: 0 -5px;
+ height:30px;
+ line-height:30px;
+ color:#8AA0CC;
+ border:solid 1px #C2CDE4;
+ overflow:hidden;
+ margin:0px;
+ padding:0px;
+}
+
+.navpath li
+{
+ list-style-type:none;
+ float:left;
+ padding-left:10px;
+ padding-right:15px;
+ background-image:url('bc_s.png');
+ background-repeat:no-repeat;
+ background-position:right;
+ color:#364D7C;
+}
+
+.navpath li.navelem a
+{
+ height:32px;
+ display:block;
+ text-decoration: none;
+ outline: none;
+ color: #283A5D;
+ font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif;
+ text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+ text-decoration: none;
+}
+
+.navpath li.navelem a:hover
+{
+ color:#6884BD;
+}
+
+.navpath li.footer
+{
+ list-style-type:none;
+ float:right;
+ padding-left:10px;
+ padding-right:15px;
+ background-image:none;
+ background-repeat:no-repeat;
+ background-position:right;
+ color:#364D7C;
+ font-size: 8pt;
+}
+
+
+div.summary
+{
+ float: right;
+ font-size: 8pt;
+ padding-right: 5px;
+ width: 50%;
+ text-align: right;
+}
+
+div.summary a
+{
+ white-space: nowrap;
+}
+
+div.ingroups
+{
+ font-size: 8pt;
+ width: 50%;
+ text-align: left;
+}
+
+div.ingroups a
+{
+ white-space: nowrap;
+}
+
+div.header
+{
+ background-image:url('nav_h.png');
+ background-repeat:repeat-x;
+ background-color: #F9FAFC;
+ margin: 0px;
+ border-bottom: 1px solid #C4CFE5;
+}
+
+div.headertitle
+{
+ padding: 5px 5px 5px 10px;
+}
+
+dl
+{
+ padding: 0 0 0 10px;
+}
+
+/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */
+dl.section
+{
+ margin-left: 0px;
+ padding-left: 0px;
+}
+
+dl.note
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #D0C000;
+}
+
+dl.warning, dl.attention
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #FF0000;
+}
+
+dl.pre, dl.post, dl.invariant
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #00D000;
+}
+
+dl.deprecated
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #505050;
+}
+
+dl.todo
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #00C0E0;
+}
+
+dl.test
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #3030E0;
+}
+
+dl.bug
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #C08050;
+}
+
+dl.section dd {
+ margin-bottom: 6px;
+}
+
+
+#projectlogo
+{
+ text-align: center;
+ vertical-align: bottom;
+ border-collapse: separate;
+}
+
+#projectlogo img
+{
+ border: 0px none;
+}
+
+#projectname
+{
+ font: 300% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 2px 0px;
+}
+
+#projectbrief
+{
+ font: 120% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 0px;
+}
+
+#projectnumber
+{
+ font: 50% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 0px;
+}
+
+#titlearea
+{
+ padding: 0px;
+ margin: 0px;
+ width: 100%;
+ border-bottom: 1px solid #5373B4;
+}
+
+.image
+{
+ text-align: center;
+}
+
+.dotgraph
+{
+ text-align: center;
+}
+
+.mscgraph
+{
+ text-align: center;
+}
+
+.diagraph
+{
+ text-align: center;
+}
+
+.caption
+{
+ font-weight: bold;
+}
+
+div.zoom
+{
+ border: 1px solid #90A5CE;
+}
+
+dl.citelist {
+ margin-bottom:50px;
+}
+
+dl.citelist dt {
+ color:#334975;
+ float:left;
+ font-weight:bold;
+ margin-right:10px;
+ padding:5px;
+}
+
+dl.citelist dd {
+ margin:2px 0;
+ padding:5px 0;
+}
+
+div.toc {
+ padding: 14px 25px;
+ background-color: #F4F6FA;
+ border: 1px solid #D8DFEE;
+ border-radius: 7px 7px 7px 7px;
+ float: right;
+ height: auto;
+ margin: 0 20px 10px 10px;
+ width: 200px;
+}
+
+div.toc li {
+ background: url("bdwn.png") no-repeat scroll 0 5px transparent;
+ font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif;
+ margin-top: 5px;
+ padding-left: 10px;
+ padding-top: 2px;
+}
+
+div.toc h3 {
+ font: bold 12px/1.2 Arial,FreeSans,sans-serif;
+ color: #4665A2;
+ border-bottom: 0 none;
+ margin: 0;
+}
+
+div.toc ul {
+ list-style: none outside none;
+ border: medium none;
+ padding: 0px;
+}
+
+div.toc li.level1 {
+ margin-left: 0px;
+}
+
+div.toc li.level2 {
+ margin-left: 15px;
+}
+
+div.toc li.level3 {
+ margin-left: 30px;
+}
+
+div.toc li.level4 {
+ margin-left: 45px;
+}
+
+.inherit_header {
+ font-weight: bold;
+ color: gray;
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.inherit_header td {
+ padding: 6px 0px 2px 5px;
+}
+
+.inherit {
+ display: none;
+}
+
+tr.heading h2 {
+ margin-top: 12px;
+ margin-bottom: 4px;
+}
+
+/* tooltip related style info */
+
+.ttc {
+ position: absolute;
+ display: none;
+}
+
+#powerTip {
+ cursor: default;
+ white-space: nowrap;
+ background-color: white;
+ border: 1px solid gray;
+ border-radius: 4px 4px 4px 4px;
+ box-shadow: 1px 1px 7px gray;
+ display: none;
+ font-size: smaller;
+ max-width: 80%;
+ opacity: 0.9;
+ padding: 1ex 1em 1em;
+ position: absolute;
+ z-index: 2147483647;
+}
+
+#powerTip div.ttdoc {
+ color: grey;
+ font-style: italic;
+}
+
+#powerTip div.ttname a {
+ font-weight: bold;
+}
+
+#powerTip div.ttname {
+ font-weight: bold;
+}
+
+#powerTip div.ttdeci {
+ color: #006318;
+}
+
+#powerTip div {
+ margin: 0px;
+ padding: 0px;
+ font: 12px/16px Roboto,sans-serif;
+}
+
+#powerTip:before, #powerTip:after {
+ content: "";
+ position: absolute;
+ margin: 0px;
+}
+
+#powerTip.n:after, #powerTip.n:before,
+#powerTip.s:after, #powerTip.s:before,
+#powerTip.w:after, #powerTip.w:before,
+#powerTip.e:after, #powerTip.e:before,
+#powerTip.ne:after, #powerTip.ne:before,
+#powerTip.se:after, #powerTip.se:before,
+#powerTip.nw:after, #powerTip.nw:before,
+#powerTip.sw:after, #powerTip.sw:before {
+ border: solid transparent;
+ content: " ";
+ height: 0;
+ width: 0;
+ position: absolute;
+}
+
+#powerTip.n:after, #powerTip.s:after,
+#powerTip.w:after, #powerTip.e:after,
+#powerTip.nw:after, #powerTip.ne:after,
+#powerTip.sw:after, #powerTip.se:after {
+ border-color: rgba(255, 255, 255, 0);
+}
+
+#powerTip.n:before, #powerTip.s:before,
+#powerTip.w:before, #powerTip.e:before,
+#powerTip.nw:before, #powerTip.ne:before,
+#powerTip.sw:before, #powerTip.se:before {
+ border-color: rgba(128, 128, 128, 0);
+}
+
+#powerTip.n:after, #powerTip.n:before,
+#powerTip.ne:after, #powerTip.ne:before,
+#powerTip.nw:after, #powerTip.nw:before {
+ top: 100%;
+}
+
+#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after {
+ border-top-color: #ffffff;
+ border-width: 10px;
+ margin: 0px -10px;
+}
+#powerTip.n:before {
+ border-top-color: #808080;
+ border-width: 11px;
+ margin: 0px -11px;
+}
+#powerTip.n:after, #powerTip.n:before {
+ left: 50%;
+}
+
+#powerTip.nw:after, #powerTip.nw:before {
+ right: 14px;
+}
+
+#powerTip.ne:after, #powerTip.ne:before {
+ left: 14px;
+}
+
+#powerTip.s:after, #powerTip.s:before,
+#powerTip.se:after, #powerTip.se:before,
+#powerTip.sw:after, #powerTip.sw:before {
+ bottom: 100%;
+}
+
+#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after {
+ border-bottom-color: #ffffff;
+ border-width: 10px;
+ margin: 0px -10px;
+}
+
+#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before {
+ border-bottom-color: #808080;
+ border-width: 11px;
+ margin: 0px -11px;
+}
+
+#powerTip.s:after, #powerTip.s:before {
+ left: 50%;
+}
+
+#powerTip.sw:after, #powerTip.sw:before {
+ right: 14px;
+}
+
+#powerTip.se:after, #powerTip.se:before {
+ left: 14px;
+}
+
+#powerTip.e:after, #powerTip.e:before {
+ left: 100%;
+}
+#powerTip.e:after {
+ border-left-color: #ffffff;
+ border-width: 10px;
+ top: 50%;
+ margin-top: -10px;
+}
+#powerTip.e:before {
+ border-left-color: #808080;
+ border-width: 11px;
+ top: 50%;
+ margin-top: -11px;
+}
+
+#powerTip.w:after, #powerTip.w:before {
+ right: 100%;
+}
+#powerTip.w:after {
+ border-right-color: #ffffff;
+ border-width: 10px;
+ top: 50%;
+ margin-top: -10px;
+}
+#powerTip.w:before {
+ border-right-color: #808080;
+ border-width: 11px;
+ top: 50%;
+ margin-top: -11px;
+}
+
+@media print
+{
+ #top { display: none; }
+ #side-nav { display: none; }
+ #nav-path { display: none; }
+ body { overflow:visible; }
+ h1, h2, h3, h4, h5, h6 { page-break-after: avoid; }
+ .summary { display: none; }
+ .memitem { page-break-inside: avoid; }
+ #doc-content
+ {
+ margin-left:0 !important;
+ height:auto !important;
+ width:auto !important;
+ overflow:inherit;
+ display:inline;
+ }
+}
+
+
+h1, .h1, h2, .h2, h3, .h3{
+ font-weight: 200 !important;
+ font-family: Helvetica-Light;
+}
+
+#navrow1, #navrow2, #navrow3, #navrow4, #navrow5 {
+ border-bottom: 1px solid #EEEEEE;
+}
+
+.adjust-right {
+ margin-left: 30px !important;
+ font-size: 1.15em !important;
+}
+.navbar{
+ border: 0px solid #222 !important;
+}
+
+
+/* Sticky footer styles
+-------------------------------------------------- */
+html,
+body {
+ height: 100%;
+ /* The html and body elements cannot have any padding or margin. */
+}
+
+/* Wrapper for page content to push down footer */
+#wrap {
+ min-height: 100%;
+ height: auto;
+ /* Negative indent footer by its height */
+ margin: 0 auto -60px;
+ /* Pad bottom by footer height */
+ padding: 0 0 60px;
+}
+
+/* Set the fixed height of the footer here */
+#footer {
+ font-size: 0.9em;
+ padding: 8px 0px;
+ background-color: #f5f5f5;
+}
+
+.footer-row {
+ line-height: 44px;
+}
+
+#footer > .container {
+ padding-left: 15px;
+ padding-right: 15px;
+}
+
+.footer-follow-icon {
+ margin-left: 3px;
+ text-decoration: none !important;
+}
+
+.footer-follow-icon img {
+ width: 20px;
+}
+
+.footer-link {
+ padding-top: 5px;
+ display: inline-block;
+ color: #999999;
+ text-decoration: none;
+}
+
+.footer-copyright {
+ text-align: center;
+}
+
+
+@media (min-width: 992px) {
+ .footer-row {
+ text-align: left;
+ }
+
+ .footer-icons {
+ text-align: right;
+ }
+}
+@media (max-width: 991px) {
+ .footer-row {
+ text-align: center;
+ }
+
+ .footer-icons {
+ text-align: center;
+ }
+}
+
+/* DOXYGEN Code Styles
+----------------------------------- */
+
+
+a.qindex {
+ font-weight: bold;
+}
+
+a.qindexHL {
+ font-weight: bold;
+ background-color: #9CAFD4;
+ color: #ffffff;
+ border: 1px double #869DCA;
+}
+
+.contents a.qindexHL:visited {
+ color: #ffffff;
+}
+
+a.code, a.code:visited, a.line, a.line:visited {
+ color: #4665A2;
+}
+
+a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
+ color: #4665A2;
+}
+
+/* @end */
+
+dl.el {
+ margin-left: -1cm;
+}
+
+pre.fragment {
+ border: 1px solid #C4CFE5;
+ background-color: #FBFCFD;
+ padding: 4px 6px;
+ margin: 4px 8px 4px 2px;
+ overflow: auto;
+ word-wrap: break-word;
+ font-size: 9pt;
+ line-height: 125%;
+ font-family: monospace, fixed;
+ font-size: 105%;
+}
+
+div.fragment {
+ padding: 4px 6px;
+ margin: 4px 8px 4px 2px;
+ border: 1px solid #C4CFE5;
+}
+
+div.line {
+ font-family: monospace, fixed;
+ font-size: 13px;
+ min-height: 13px;
+ line-height: 1.0;
+ text-wrap: unrestricted;
+ white-space: -moz-pre-wrap; /* Moz */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: pre-wrap; /* CSS3 */
+ word-wrap: break-word; /* IE 5.5+ */
+ text-indent: -53px;
+ padding-left: 53px;
+ padding-bottom: 0px;
+ margin: 0px;
+ -webkit-transition-property: background-color, box-shadow;
+ -webkit-transition-duration: 0.5s;
+ -moz-transition-property: background-color, box-shadow;
+ -moz-transition-duration: 0.5s;
+ -ms-transition-property: background-color, box-shadow;
+ -ms-transition-duration: 0.5s;
+ -o-transition-property: background-color, box-shadow;
+ -o-transition-duration: 0.5s;
+ transition-property: background-color, box-shadow;
+ transition-duration: 0.5s;
+}
+
+div.line.glow {
+ background-color: cyan;
+ box-shadow: 0 0 10px cyan;
+}
+
+
+span.lineno {
+ padding-right: 4px;
+ text-align: right;
+ border-right: 2px solid #0F0;
+ background-color: #E8E8E8;
+ white-space: pre;
+}
+span.lineno a {
+ background-color: #D8D8D8;
+}
+
+span.lineno a:hover {
+ background-color: #C8C8C8;
+}
+
+div.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ font-weight: bold;
+}
+
+div.groupText {
+ margin-left: 16px;
+ font-style: italic;
+}
+
+/* @group Code Colorization */
+
+span.keyword {
+ color: #008000
+}
+
+span.keywordtype {
+ color: #604020
+}
+
+span.keywordflow {
+ color: #e08000
+}
+
+span.comment {
+ color: #800000
+}
+
+span.preprocessor {
+ color: #806020
+}
+
+span.stringliteral {
+ color: #002080
+}
+
+span.charliteral {
+ color: #008080
+}
+
+span.vhdldigit {
+ color: #ff00ff
+}
+
+span.vhdlchar {
+ color: #000000
+}
+
+span.vhdlkeyword {
+ color: #700070
+}
+
+span.vhdllogic {
+ color: #ff0000
+}
+
+blockquote {
+ background-color: #F7F8FB;
+ border-left: 2px solid #9CAFD4;
+ margin: 0 24px 0 4px;
+ padding: 0 12px 0 16px;
+}
diff --git a/libccnx-common/documentation/doxygen-extras/doxy-boot.js b/libccnx-common/documentation/doxygen-extras/doxy-boot.js
new file mode 100644
index 00000000..5ee5fa37
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/doxy-boot.js
@@ -0,0 +1,120 @@
+$( document ).ready(function() {
+
+ $("div.headertitle").addClass("page-header");
+ $("div.title").addClass("h1");
+
+ $('li > a[href="index.html"] > span').before("<i class='fa fa-cog'></i> ");
+ $('li > a[href="modules.html"] > span').before("<i class='fa fa-square'></i> ");
+ $('li > a[href="namespaces.html"] > span').before("<i class='fa fa-bars'></i> ");
+ $('li > a[href="annotated.html"] > span').before("<i class='fa fa-list-ul'></i> ");
+ $('li > a[href="classes.html"] > span').before("<i class='fa fa-book'></i> ");
+ $('li > a[href="inherits.html"] > span').before("<i class='fa fa-sitemap'></i> ");
+ $('li > a[href="functions.html"] > span').before("<i class='fa fa-list'></i> ");
+ $('li > a[href="functions_func.html"] > span').before("<i class='fa fa-list'></i> ");
+ $('li > a[href="functions_vars.html"] > span').before("<i class='fa fa-list'></i> ");
+ $('li > a[href="functions_enum.html"] > span').before("<i class='fa fa-list'></i> ");
+ $('li > a[href="functions_eval.html"] > span').before("<i class='fa fa-list'></i> ");
+ $('img[src="ftv2ns.png"]').replaceWith('<span class="label label-danger">N</span> ');
+ $('img[src="ftv2cl.png"]').replaceWith('<span class="label label-danger">C</span> ');
+
+ $("ul.tablist").addClass("nav nav-pills nav-justified");
+ $("ul.tablist").css("margin-top", "0.5em");
+ $("ul.tablist").css("margin-bottom", "0.5em");
+ $("li.current").addClass("active");
+ $("iframe").attr("scrolling", "yes");
+
+ $("#nav-path > ul").addClass("breadcrumb");
+
+ $("table.params").addClass("table");
+ $("div.ingroups").wrapInner("<small></small>");
+ $("div.levels").css("margin", "0.5em");
+ $("div.levels > span").addClass("btn btn-default btn-xs");
+ $("div.levels > span").css("margin-right", "0.25em");
+
+ $("table.directory").addClass("table table-striped");
+ $("div.summary > a").addClass("btn btn-default btn-xs");
+ $("table.fieldtable").addClass("table");
+ $(".fragment").addClass("well");
+ $(".memitem").addClass("panel panel-default");
+ $(".memproto").addClass("panel-heading");
+ $(".memdoc").addClass("panel-body");
+ $("span.mlabel").addClass("label label-info");
+
+ $("table.memberdecls").addClass("table");
+ $("[class^=memitem]").addClass("active");
+
+ $("div.ah").addClass("btn btn-default");
+ $("span.mlabels").addClass("pull-right");
+ $("table.mlabels").css("width", "100%")
+ $("td.mlabels-right").addClass("pull-right");
+
+ $("div.ttc").addClass("panel panel-primary");
+ $("div.ttname").addClass("panel-heading");
+ $("div.ttname a").css("color", 'white');
+ $("div.ttdef,div.ttdoc,div.ttdeci").addClass("panel-body");
+
+ $('#MSearchBox').parent().remove();
+
+ $('div.fragment.well div.line:first').css('margin-top', '15px');
+ $('div.fragment.well div.line:last').css('margin-bottom', '15px');
+
+ $('table.doxtable').removeClass('doxtable').addClass('table table-striped table-bordered').each(function(){
+ $(this).prepend('<thead></thead>');
+ $(this).find('tbody > tr:first').prependTo($(this).find('thead'));
+
+ $(this).find('td > span.success').parent().addClass('success');
+ $(this).find('td > span.warning').parent().addClass('warning');
+ $(this).find('td > span.danger').parent().addClass('danger');
+ });
+
+
+
+ if($('div.fragment.well div.ttc').length > 0)
+ {
+ $('div.fragment.well div.line:first').parent().removeClass('fragment well');
+ }
+
+ $('table.memberdecls').find('.memItemRight').each(function(){
+ $(this).contents().appendTo($(this).siblings('.memItemLeft'));
+ $(this).siblings('.memItemLeft').attr('align', 'left');
+ });
+
+ function getOriginalWidthOfImg(img_element) {
+ var t = new Image();
+ t.src = (img_element.getAttribute ? img_element.getAttribute("src") : false) || img_element.src;
+ return t.width;
+ }
+
+ $('div.dyncontent').find('img').each(function(){
+ if(getOriginalWidthOfImg($(this)[0]) > $('#content>div.container').width())
+ $(this).css('width', '100%');
+ });
+
+ $(".memitem").removeClass('memitem');
+ $(".memproto").removeClass('memproto');
+ $(".memdoc").removeClass('memdoc');
+ $("span.mlabel").removeClass('mlabel');
+ $("table.memberdecls").removeClass('memberdecls');
+ $("[class^=memitem]").removeClass('memitem');
+ $("span.mlabels").removeClass('mlabels');
+ $("table.mlabels").removeClass('mlabels');
+ $("td.mlabels-right").removeClass('mlabels-right');
+ $(".navpath").removeClass('navpath');
+ $("li.navelem").removeClass('navelem');
+ $("a.el").removeClass('el');
+ $("div.ah").removeClass('ah');
+ $("div.header").removeClass("header");
+
+ $('.mdescLeft').each(function(){
+ if($(this).html()=="&nbsp;") {
+ $(this).siblings('.mdescRight').attr('colspan', 2);
+ $(this).remove();
+ }
+ });
+ $('td.memItemLeft').each(function(){
+ if($(this).siblings('.memItemRight').html()=="") {
+ $(this).attr('colspan', 2);
+ $(this).siblings('.memItemRight').remove();
+ }
+ });
+}); \ No newline at end of file
diff --git a/libccnx-common/documentation/doxygen-extras/doxygen-bootstrap.js b/libccnx-common/documentation/doxygen-extras/doxygen-bootstrap.js
new file mode 100755
index 00000000..2ddb6474
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/doxygen-bootstrap.js
@@ -0,0 +1,119 @@
+/* Annotate the html output from doxygen with the necessary classes
+ * for the twitter bootstrap.
+ */
+$(document).ready(function() {
+ $("div.headertitle").addClass("page-header");
+ $("div.title").addClass("h1");
+
+ $('li > a[href="index.html"] > span').before("<i class='fa fa-cog'></i> ");
+ $('li > a[href="modules.html"] > span').before("<i class='fa fa-square'></i> ");
+ $('li > a[href="namespaces.html"] > span').before("<i class='fa fa-bars'></i> ");
+ $('li > a[href="annotated.html"] > span').before("<i class='fa fa-list-ul'></i> ");
+ $('li > a[href="classes.html"] > span').before("<i class='fa fa-book'></i> ");
+ $('li > a[href="inherits.html"] > span').before("<i class='fa fa-sitemap'></i> ");
+ $('li > a[href="functions.html"] > span').before("<i class='fa fa-list'></i> ");
+ $('li > a[href="functions_func.html"] > span').before("<i class='fa fa-list'></i> ");
+ $('li > a[href="functions_vars.html"] > span').before("<i class='fa fa-list'></i> ");
+ $('li > a[href="functions_enum.html"] > span').before("<i class='fa fa-list'></i> ");
+ $('li > a[href="functions_eval.html"] > span').before("<i class='fa fa-list'></i> ");
+ $('img[src="ftv2ns.png"]').replaceWith('<span class="label label-danger">N</span> ');
+ $('img[src="ftv2cl.png"]').replaceWith('<span class="label label-danger">C</span> ');
+
+ $("ul.tablist").addClass("nav nav-pills nav-justified");
+ $("ul.tablist").css("margin-top", "0.5em");
+ $("ul.tablist").css("margin-bottom", "0.5em");
+ $("li.current").addClass("active");
+ $("iframe").attr("scrolling", "yes");
+
+ $("#nav-path > ul").addClass("breadcrumb");
+
+ $("table.params").addClass("table");
+ $("div.ingroups").wrapInner("<small></small>");
+ $("div.levels").css("margin", "0.5em");
+ $("div.levels > span").addClass("btn btn-default btn-xs");
+ $("div.levels > span").css("margin-right", "0.25em");
+
+ $("table.directory").addClass("table table-striped");
+ $("div.summary > a").addClass("btn btn-default btn-xs");
+ $("table.fieldtable").addClass("table");
+ $(".fragment").addClass("well");
+ $(".memitem").addClass("panel panel-default");
+ $(".memproto").addClass("panel-heading");
+ $(".memdoc").addClass("panel-body");
+ $("span.mlabel").addClass("label label-info");
+
+ $("table.memberdecls").addClass("table");
+ $("[class^=memitem]").addClass("active");
+
+ $("div.ah").addClass("btn btn-default");
+ $("span.mlabels").addClass("pull-right");
+ $("table.mlabels").css("width", "100%")
+ $("td.mlabels-right").addClass("pull-right");
+
+ $("div.ttc").addClass("panel panel-primary");
+ $("div.ttname").addClass("panel-heading");
+ $("div.ttname a").css("color", 'white');
+ $("div.ttdef,div.ttdoc,div.ttdeci").addClass("panel-body");
+
+ $('#MSearchBox').parent().remove();
+
+ $('div.fragment.well div.line:first').css('margin-top', '15px');
+ $('div.fragment.well div.line:last').css('margin-bottom', '15px');
+
+ $('table.doxtable').removeClass('doxtable').addClass('table table-striped table-bordered').each(function(){
+ $(this).prepend('<thead></thead>');
+ $(this).find('tbody > tr:first').prependTo($(this).find('thead'));
+
+ $(this).find('td > span.success').parent().addClass('success');
+ $(this).find('td > span.warning').parent().addClass('warning');
+ $(this).find('td > span.danger').parent().addClass('danger');
+ });
+
+ if($('div.fragment.well div.ttc').length > 0) {
+ $('div.fragment.well div.line:first').parent().removeClass('fragment well');
+ }
+
+ $('table.memberdecls').find('.memItemRight').each(function(){
+ $(this).contents().appendTo($(this).siblings('.memItemLeft'));
+ $(this).siblings('.memItemLeft').attr('align', 'left');
+ });
+
+ function getOriginalWidthOfImg(img_element) {
+ var t = new Image();
+ t.src = (img_element.getAttribute ? img_element.getAttribute("src") : false) || img_element.src;
+ return t.width;
+ }
+
+ $('div.dyncontent').find('img').each(function(){
+ if(getOriginalWidthOfImg($(this)[0]) > $('#content>div.container').width())
+ $(this).css('width', '100%');
+ });
+
+ $(".memitem").removeClass('memitem');
+ $(".memproto").removeClass('memproto');
+ $(".memdoc").removeClass('memdoc');
+ $("span.mlabel").removeClass('mlabel');
+ $("table.memberdecls").removeClass('memberdecls');
+ $("[class^=memitem]").removeClass('memitem');
+ $("span.mlabels").removeClass('mlabels');
+ $("table.mlabels").removeClass('mlabels');
+ $("td.mlabels-right").removeClass('mlabels-right');
+ $(".navpath").removeClass('navpath');
+ $("li.navelem").removeClass('navelem');
+ $("a.el").removeClass('el');
+ $("div.ah").removeClass('ah');
+ $("div.header").removeClass("header");
+
+ $('.mdescLeft').each(function(){
+ if($(this).html()=="&nbsp;") {
+ $(this).siblings('.mdescRight').attr('colspan', 2);
+ $(this).remove();
+ }
+ });
+ $('td.memItemLeft').each(function(){
+ if($(this).siblings('.memItemRight').html()=="") {
+ $(this).attr('colspan', 2);
+ $(this).siblings('.memItemRight').remove();
+ }
+ });
+});
diff --git a/libccnx-common/documentation/doxygen-extras/footer.html b/libccnx-common/documentation/doxygen-extras/footer.html
new file mode 100755
index 00000000..10ea2600
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/footer.html
@@ -0,0 +1,31 @@
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+</div>
+<!--END GENERATE_TREEVIEW-->
+</div>
+</div>
+</div>
+</div>
+</div>
+<hr class="footer"/>
+ <div class="container footer">
+Copyright (c) 2017 Cisco and/or its affiliates.<br/>
+$datetime
+<!-- Start of StatCounter Code for Default Guide -->
+<script type="text/javascript">
+//<![CDATA[
+var sc_project=11084575;
+var sc_invisible=0;
+var sc_security="bed914f8";
+var scJsHost = (("https:" == document.location.protocol) ? "https://secure." : "http://www.");
+document.write("<sc"+"ript type='text/javascript' src='" + scJsHost+ "statcounter.com/counter/counter_xhtml.js'></"+"script>");
+//]]>
+</script>
+<noscript>
+<div class="statcounter">
+<a title="shopify site analytics" href="http://statcounter.com/shopify/" class="statcounter">
+<img class="statcounter" src="http://c.statcounter.com/11084575/0/bed914f8/0/" alt="statcounter" />
+</a></div></noscript>
+ </div>
+<!-- End of StatCounter Code for Default Guide -->
+</body>
+</html>
diff --git a/libccnx-common/documentation/doxygen-extras/header.html b/libccnx-common/documentation/doxygen-extras/header.html
new file mode 100755
index 00000000..9be163ba
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/header.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <!-- For Mobile Devices -->
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+
+ <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+ <meta name="generator" content="Doxygen $doxygenversion"/>
+
+ <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
+
+ <!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+ <!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+ <!--<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>-->
+ <script type="text/javascript" src="$relpath^dynsections.js"></script>
+ $treeview
+ $search
+ $mathjax
+ <link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
+ <link href="masthead.css" rel="stylesheet" type="text/css" />
+ $extrastylesheet
+
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
+ <script type="text/javascript" src="$relpath^doxygen-bootstrap.js"></script>
+ </head>
+ <body>
+ <div class="container masthead">
+ <div class="navbar-header">
+ <img src="parc_black_solid.png" \>
+ </div>
+ </div>
+ <nav class="navbar navbar-default" role="navigation">
+ <div class="container">
+ <div class="navbar-header">
+ <a class="navbar-brand">$projectname $projectnumber</a>
+ </div>
+ </div>
+ </nav>
+ <div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+ <div class="content" id="content">
+ <div class="container">
+ <div class="row">
+ <div class="col-sm-12 panel panel-default" style="padding-bottom: 15px;">
+ <div style="margin-bottom: 15px;">
+<!-- end header part -->
diff --git a/libccnx-common/documentation/doxygen-extras/masthead.css b/libccnx-common/documentation/doxygen-extras/masthead.css
new file mode 100644
index 00000000..7827e079
--- /dev/null
+++ b/libccnx-common/documentation/doxygen-extras/masthead.css
@@ -0,0 +1,9 @@
+.masthead {
+ border-bottom: 1px dotted black;
+ margin-top: 20.5px;
+}
+
+.masthead img {
+ height: 50px;
+ margin-bottom: 20px;
+}
diff --git a/libccnx-common/documentation/examples/README.md b/libccnx-common/documentation/examples/README.md
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/libccnx-common/documentation/examples/README.md
diff --git a/libccnx-common/documentation/images/parc_black_solid.png b/libccnx-common/documentation/images/parc_black_solid.png
new file mode 100644
index 00000000..6abcf2f4
--- /dev/null
+++ b/libccnx-common/documentation/images/parc_black_solid.png
Binary files differ
diff --git a/libccnx-common/documentation/libccnx-stage1.doxygen.in b/libccnx-common/documentation/libccnx-stage1.doxygen.in
new file mode 100644
index 00000000..4fc9fc11
--- /dev/null
+++ b/libccnx-common/documentation/libccnx-stage1.doxygen.in
@@ -0,0 +1,2385 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "CCNx Common Library"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+# A collection of general purpose algorithms and concurrency, security, and logging structures and functions.
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = generated-documentation
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+#.*/Libparc
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE = doxygen.log
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = @CMAKE_CURRENT_SOURCE_DIR@/../ccnx/common
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE = @CMAKE_CURRENT_SOURCE_DIR@/../ccnx/common/internal @CMAKE_CURRENT_SOURCE_DIR@/ccnx/common/codec/testdata/
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = */examples/* \
+ */tests/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH = examples
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER = @CMAKE_CURRENT_SOURCE_DIR@/doxygen-extras/header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER = @CMAKE_CURRENT_SOURCE_DIR@/doxygen-extras/footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET = @CMAKE_CURRENT_SOURCE_DIR@/doxygen-extras/customdoxygen.css @CMAKE_CURRENT_SOURCE_DIR@/doxygen-extras/masthead.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES = @CMAKE_CURRENT_SOURCE_DIR@/doxygen-extras/doxygen-bootstrap.js @CMAKE_CURRENT_SOURCE_DIR@/images/parc_black_solid.png
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = com.parc.csl.Libparc
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = com.parc.csl
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = PARC
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES = ../../Longbow/documentation/longbow.doctags=https://parc.github.io/LongBow/
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE = libccnx.doctags
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = NO
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/libccnx-common/documentation/libccnx-stage2.doxygen.in b/libccnx-common/documentation/libccnx-stage2.doxygen.in
new file mode 100644
index 00000000..f920d841
--- /dev/null
+++ b/libccnx-common/documentation/libccnx-stage2.doxygen.in
@@ -0,0 +1,2389 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "CCNx Common Library"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+# A collection of general purpose algorithms and concurrency, security, and logging structures and functions.
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = generated-documentation
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+#.*/Libparc
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE = doxygen.log
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = @CMAKE_CURRENT_SOURCE_DIR@/../ccnx/common
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE = @CMAKE_CURRENT_SOURCE_DIR@/../ccnx/common/internal @CMAKE_CURRENT_SOURCE_DIR@/ccnx/common/codec/testdata/
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = */examples/* \
+ */tests/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH = examples
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER = @CMAKE_CURRENT_SOURCE_DIR@/doxygen-extras/header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER = @CMAKE_CURRENT_SOURCE_DIR@/doxygen-extras/footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET = @CMAKE_CURRENT_SOURCE_DIR@/doxygen-extras/customdoxygen.css @CMAKE_CURRENT_SOURCE_DIR@/doxygen-extras/masthead.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES = @CMAKE_CURRENT_SOURCE_DIR@/doxygen-extras/doxygen-bootstrap.js @CMAKE_CURRENT_SOURCE_DIR@/images/parc_black_solid.png
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = com.parc.csl.Libparc
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = com.parc.csl
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = PARC
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES = libccnx_api_notify.doctags=../../libccnx_api_notify-documentation/html \
+ libccnx_api_portal.doctags=../../libccnx_api_portal-documentation/html \
+ libccnx_api_control.doctags=../../libccnx_api_control-documentation/html \
+ ../../Libparc/documentation/libparc.doctags=https://parc.github.io/Libparc \
+ ../../Longbow/documentation/longbow.doctags=https://parc.github.io/LongBow
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE = libccnx.doctags
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = NO
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/libccnx-common/documentation/libccnx_api_control-stage1.doxygen b/libccnx-common/documentation/libccnx_api_control-stage1.doxygen
new file mode 100644
index 00000000..7b52c73b
--- /dev/null
+++ b/libccnx-common/documentation/libccnx_api_control-stage1.doxygen
@@ -0,0 +1,2424 @@
+# Doxyfile 1.8.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = CCNxStackControlAPI
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = ""
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = libccnx_api_control-documentation
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= NO
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../ccnx/api/control
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = */examples/* \
+ */tests/* \
+ */test/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET = stylesheet.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = com.parc.csl.libccnx
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = com.parc.csl
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = PARC
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+#TAGFILES = ../../Libparc/documentation/libparc.doctags=../../Libparc/documentation/Jekyll/PARC/parc-function-documentation
+# libccnx.doctags=./
+
+#TAGFILES = libccnx.doctags=../../libccnx-documentation/html
+# libccnx_api_notify.doctags=../../libccnx_api_notify-documentation/html \
+# libccnx_api_portal.doctags=../../libccnx_api_portal-documentation/html
+# libccnx_api_keyvalue.doctags=../../libccnx_api_keyvalue-documentation/html \
+# libccnx_api_mqueue.doctags=../../libccnx_api_mqueue-documentation/html \
+# libparc.doctags=../../../../libparc/documentation/libparc-documentation/html
+
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE = libccnx_api_control.doctags
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = NO
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/libccnx-common/documentation/libccnx_api_control-stage2.doxygen b/libccnx-common/documentation/libccnx_api_control-stage2.doxygen
new file mode 100644
index 00000000..f03a2d6b
--- /dev/null
+++ b/libccnx-common/documentation/libccnx_api_control-stage2.doxygen
@@ -0,0 +1,2424 @@
+# Doxyfile 1.8.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = CCNxStackControlAPI
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = ""
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = libccnx_api_control-documentation
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../ccnx/api/control
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = */examples/* \
+ */tests/* \
+ */test/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET = stylesheet.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = com.parc.csl.libccnx
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = com.parc.csl
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = PARC
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+#TAGFILES = ../../Libparc/documentation/libparc.doctags=../../Libparc/documentation/Jekyll/PARC/parc-function-documentation
+# libccnx.doctags=./
+
+TAGFILES = libccnx_api_notify.doctags=../../libccnx_api_notify-documentation/html \
+ libccnx_api_portal.doctags=../../libccnx_api_portal-documentation/html \
+ libccnx.doctags=../../libccnx-documentation/html \
+ ../../Libparc/documentation/libparc.doctags= \
+ ../../Longbow/documentation/longbow.doctags=
+
+
+
+# When a file name is specified after FILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+#GENERATE_TAGFILE = libccnx_api_control.doctags
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/libccnx-common/documentation/libccnx_api_notify-stage1.doxygen b/libccnx-common/documentation/libccnx_api_notify-stage1.doxygen
new file mode 100644
index 00000000..0629dbdd
--- /dev/null
+++ b/libccnx-common/documentation/libccnx_api_notify-stage1.doxygen
@@ -0,0 +1,2422 @@
+# Doxyfile 1.8.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = CCNxStackNotificationAPI
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = ""
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = libccnx_api_notify-documentation
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= NO
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../ccnx/api/notify
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = */examples/* \
+ */tests/* \
+ */test/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET = stylesheet.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = com.parc.csl.libccnx
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = com.parc.csl
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = PARC
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+
+#TAGFILES = libccnx.doctags=../../libccnx-documentation/html
+# libccnx_api_portal.doctags=../../libccnx_api_portal-documentation/html \
+# libccnx_api_control.doctags=../../libccnx_api_control-documentation/html \
+# libccnx_api_keyvalue.doctags=../../libccnx_api_keyvalue-documentation/html \
+# libccnx_api_mqueue.doctags=../../libccnx_api_mqueue-documentation/html
+# libparc.doctags=../../../../libparc/documentation/libparc-documentation/html
+
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE = libccnx_api_notify.doctags
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = NO
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/libccnx-common/documentation/libccnx_api_notify-stage2.doxygen b/libccnx-common/documentation/libccnx_api_notify-stage2.doxygen
new file mode 100644
index 00000000..5990ff6a
--- /dev/null
+++ b/libccnx-common/documentation/libccnx_api_notify-stage2.doxygen
@@ -0,0 +1,2420 @@
+# Doxyfile 1.8.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = CCNxStackNotificationAPI
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = ""
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = libccnx_api_notify-documentation
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../ccnx/api/notify
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = */examples/* \
+ */tests/* \
+ */test/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET = stylesheet.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = com.parc.csl.libccnx
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = com.parc.csl
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = PARC
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES = libccnx.doctags=../../libccnx-documentation/html \
+ libccnx_api_portal.doctags=../../libccnx_api_portal-documentation/html \
+ libccnx_api_control.doctags=../../libccnx_api_control-documentation/html \
+ ../../../cframework/libparc/documentation/libparc.doctags= \
+ ../../../cframework/longbow/documentation/longbow.doctags=
+
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+#GENERATE_TAGFILE = libccnx_api_notify.doctags
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/libccnx-common/documentation/libccnx_api_portal-stage1.doxygen b/libccnx-common/documentation/libccnx_api_portal-stage1.doxygen
new file mode 100644
index 00000000..edf05ec0
--- /dev/null
+++ b/libccnx-common/documentation/libccnx_api_portal-stage1.doxygen
@@ -0,0 +1,2424 @@
+# Doxyfile 1.8.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = CCNxPortal
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "The low-level CCN API"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = libccnx_api_portal-documentation
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= NO
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../ccnx/api/ccnx_Portal
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+#TAGFILES = libccnx.doctags=../libccnx previously in file
+# TAGFILES = libccnx.doctags=../../libccnx-documentation/html
+# libccnx_api_notify.doctags=../../libccnx_api_notify-documentation/html
+
+#TAGFILES = libccnx.doctags=../../libccnx-documentation/html
+# libccnx_api_notify.doctags=../../libccnx_api_notify-documentation/html \
+# libccnx_api_control.doctags=../../libccnx_api_control-documentation/html
+# libccnx_api_keyvalue.doctags=../../libccnx_api_keyvalue-documentation/html \
+# libccnx_api_mqueue.doctags=../../libccnx_api_mqueue-documentation/html
+# libparc.doctags=../../../../libparc/documentation/libparc-documentation/html
+
+
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE = libccnx_api_portal.doctags
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = NO
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/libccnx-common/documentation/libccnx_api_portal-stage2.doxygen b/libccnx-common/documentation/libccnx_api_portal-stage2.doxygen
new file mode 100644
index 00000000..c0984c37
--- /dev/null
+++ b/libccnx-common/documentation/libccnx_api_portal-stage2.doxygen
@@ -0,0 +1,2423 @@
+# Doxyfile 1.8.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = CCNxPortal
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "The low-level CCN API"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = libccnx_api_portal-documentation
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../ccnx/api/ccnx_Portal
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+#TAGFILES = libccnx.doctags=../libccnx previously in file
+# TAGFILES = libccnx.doctags=../../libccnx-documentation/html
+# libccnx_api_notify.doctags=../../libccnx_api_notify-documentation/html
+
+
+TAGFILES = libccnx_api_notify.doctags=../../libccnx_api_notify-documentation/html \
+ libccnx.doctags=../../libccnx-documentation/html \
+ libccnx_api_control.doctags=../../libccnx_api_control-documentation/html \
+ ../../../cframework/libparc/documentation/libparc.doctags= \
+ ../../../cframework/longbow/documentation/longbow.doctags=
+
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+#GENERATE_TAGFILE = libccnx_api_portal.doctags
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/libccnx-common/documentation/librta-stage1.doxygen b/libccnx-common/documentation/librta-stage1.doxygen
new file mode 100644
index 00000000..f5b73e8b
--- /dev/null
+++ b/libccnx-common/documentation/librta-stage1.doxygen
@@ -0,0 +1,2415 @@
+# Doxyfile 1.8.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = CCNxCommonAPI
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = ""
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = librta-documentation
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= NO
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../ccnx/transport
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = */examples/* \
+ */tests/* \
+ */test/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET = stylesheet.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = com.parc.csl.libccnx
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = com.parc.csl
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = PARC
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+#TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE = libccnx_transport_rta.doctags
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = NO
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/libccnx-common/documentation/librta-stage2.doxygen b/libccnx-common/documentation/librta-stage2.doxygen
new file mode 100644
index 00000000..a2a8b335
--- /dev/null
+++ b/libccnx-common/documentation/librta-stage2.doxygen
@@ -0,0 +1,2420 @@
+# Doxyfile 1.8.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = Transport Framework
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = librta-documentation
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../ccnx/transport
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = */examples/* \
+ */tests/* \
+ */test/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET = stylesheet.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = com.parc.csl.libccnx
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = com.parc.csl
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = PARC
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES = libccnx_api_notify.doctags=../../libccnx_api_notify-documentation/html \
+ libccnx_api_portal.doctags=../../libccnx_api_portal-documentation/html \
+ libccnx_api_control.doctags=../../libccnx_api_control-documentation/html \
+ ../../../cframework/libparc/documentation/libparc.doctags= \
+ ../../../cframework/longbow/documentation/longbow.doctags=
+
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+#GENERATE_TAGFILE = libccnx_transport_rta.doctags
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/libccnx-common/documentation/stylesheet.css b/libccnx-common/documentation/stylesheet.css
new file mode 100644
index 00000000..fb5cda7c
--- /dev/null
+++ b/libccnx-common/documentation/stylesheet.css
@@ -0,0 +1,47 @@
+body {
+ xbackground-color: #111111;
+ xcolor: white;
+ margin: 0;
+ padding: 11% 11% 0 11%;
+}
+
+xdiv#top {
+ margin: 0 11% 0 11%;
+ padding: 4em 3% 4em 3%;
+ background-color: white;
+ color: black;
+ border-radius: 8px;
+}
+
+xdiv.header {
+ margin: 0 11% 0 11%;
+ padding: 4em 3% 4em 3%;
+ background-color: grey;
+ color: black;
+ border-radius: 8px;
+}
+
+div.contents {
+ xbackground-image: url(noise_gradient.jpg);
+ xbackground-repeat: no-repeat;
+ /*margin: 0 11% 0 11%;*/
+ /*padding: 4em 3% 4em 3%;*/
+/* background-color: white;*/
+ xcolor: white;
+ xborder-radius: 8px;
+}
+
+x#titlearea {
+ border: 2px solid red;
+ background-color: white;
+ color: black;
+}
+
+xhr.footer {
+ display: none;
+}
+
+x.footer {
+ background-color: #AAA;
+ color: black;
+}