aboutsummaryrefslogtreecommitdiffstats
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
parent9b30fc10fb1cbebe651e5a107e8ca5b24de54675 (diff)
Initial commit: ccnxlibs.
Change-Id: I1b376527a7dd01a6b9e083a6cb646955902f45c0 Signed-off-by: Luca Muscariello <lumuscar+fdio@cisco.com>
-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
-rw-r--r--libccnx-portal/.gitignore98
-rw-r--r--libccnx-portal/AUTHORS9
-rw-r--r--libccnx-portal/BASE_VERSION1
-rw-r--r--libccnx-portal/CMakeLists.txt89
-rw-r--r--libccnx-portal/LICENSE14
-rw-r--r--libccnx-portal/README.md82
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/CMakeLists.txt52
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.c44
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.h54
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.c257
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.h529
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.c140
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.h44
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.c258
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.h396
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.c39
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.h52
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.c136
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.h236
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.c452
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.h82
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.c191
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.h330
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/command-line/.gitignore5
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/command-line/CMakeLists.txt19
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-client.c159
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-read.c136
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-write.c21
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-server.c218
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.c44
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.h54
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.c44
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.h54
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/config.h.in3
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/.gitignore6
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/Abstract.tex9
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/CCNTransportStackPortal.tex46
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/Document.tex501
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/PARCTwoColumn.cls280
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/Packages.tex46
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/README.md16
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/Stack Diagram.grafflebin0 -> 9624 bytes
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/StackDiagram.pdfbin0 -> 29817 bytes
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/Title.tex15
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/TransportStackFramework.pdfbin0 -> 26633 bytes
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/parc_black_solid.pngbin0 -> 24543 bytes
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/documentation/sample.bib8
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/test/.gitignore9
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/test/CMakeLists.txt18
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/test/LOG25
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_Portal.c826
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAPI.c175
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAnchor.c286
-rw-r--r--libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalFactory.c245
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalRTA.c217
-rwxr-xr-xlibccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalStack.c366
-rw-r--r--libccnx-portal/cmake/Modules/FindCCNX_Common.cmake39
-rw-r--r--libccnx-portal/cmake/Modules/FindCCNX_Transport_Rta.cmake50
-rw-r--r--libccnx-portal/cmake/Modules/FindLibEvent.cmake47
-rw-r--r--libccnx-portal/cmake/Modules/FindLibparc.cmake39
-rw-r--r--libccnx-portal/cmake/Modules/FindLongBow.cmake44
-rw-r--r--libccnx-portal/cmake/Modules/FindUncrustify.cmake8
-rw-r--r--libccnx-portal/cmake/Modules/detectCacheSize.cmake21
-rw-r--r--libccnx-portal/cmake/Modules/version.cmake15
-rwxr-xr-xlibccnx-portal/cmake/get_version.sh20
-rw-r--r--libccnx-portal/documentation/.gitignore9
-rw-r--r--libccnx-portal/documentation/CMakeLists.txt20
-rw-r--r--libccnx-portal/documentation/DoxygenLayout.xml196
-rw-r--r--libccnx-portal/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css470
-rw-r--r--libccnx-portal/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css.map1
-rw-r--r--libccnx-portal/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.min.css5
-rw-r--r--libccnx-portal/documentation/doxygen-extras/bootstrap/css/bootstrap.css6332
-rw-r--r--libccnx-portal/documentation/doxygen-extras/bootstrap/css/bootstrap.css.map1
-rw-r--r--libccnx-portal/documentation/doxygen-extras/bootstrap/css/bootstrap.min.css5
-rw-r--r--libccnx-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eotbin0 -> 20335 bytes
-rw-r--r--libccnx-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.svg229
-rw-r--r--libccnx-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttfbin0 -> 41280 bytes
-rw-r--r--libccnx-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woffbin0 -> 23320 bytes
-rw-r--r--libccnx-portal/documentation/doxygen-extras/bootstrap/js/bootstrap.js2320
-rw-r--r--libccnx-portal/documentation/doxygen-extras/bootstrap/js/bootstrap.min.js7
-rw-r--r--libccnx-portal/documentation/doxygen-extras/bootstrap/js/npm.js13
-rw-r--r--libccnx-portal/documentation/doxygen-extras/customdoxygen.css1705
-rw-r--r--libccnx-portal/documentation/doxygen-extras/doxy-boot.js120
-rwxr-xr-xlibccnx-portal/documentation/doxygen-extras/doxygen-bootstrap.js119
-rwxr-xr-xlibccnx-portal/documentation/doxygen-extras/footer.html11
-rwxr-xr-xlibccnx-portal/documentation/doxygen-extras/header.html42
-rw-r--r--libccnx-portal/documentation/doxygen-extras/masthead.css9
-rw-r--r--libccnx-portal/documentation/images/noise_gradient.jpgbin0 -> 6823 bytes
-rw-r--r--libccnx-portal/documentation/libccnx_api_portal-stage1.doxygen.in2428
-rw-r--r--libccnx-portal/documentation/libccnx_api_portal-stage2.doxygen.in2406
-rw-r--r--libccnx-portal/documentation/stylesheet.css47
-rw-r--r--libccnx-transport-rta/.gitignore98
-rw-r--r--libccnx-transport-rta/AUTHORS9
-rw-r--r--libccnx-transport-rta/BASE_VERSION1
-rw-r--r--libccnx-transport-rta/CMakeLists.txt78
-rw-r--r--libccnx-transport-rta/LICENSE12
-rw-r--r--libccnx-transport-rta/README.md87
-rw-r--r--libccnx-transport-rta/ccnx/CMakeLists.txt4
-rw-r--r--libccnx-transport-rta/ccnx/api/CMakeLists.txt2
-rw-r--r--libccnx-transport-rta/ccnx/api/control/CMakeLists.txt91
-rw-r--r--libccnx-transport-rta/ccnx/api/control/README.txt274
-rw-r--r--libccnx-transport-rta/ccnx/api/control/ccnxControlAPI_About.c44
-rw-r--r--libccnx-transport-rta/ccnx/api/control/ccnxControlAPI_About.h54
-rw-r--r--libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.c449
-rw-r--r--libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.h456
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_Acks.c133
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_Acks.h149
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_Address.c502
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_Address.h599
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_AddressList.c206
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_AddressList.h222
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_CancelFlow.c100
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_CancelFlow.h108
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_Connection.c308
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_Connection.h320
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ConnectionEthernet.c294
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ConnectionEthernet.h281
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ConnectionList.c160
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ConnectionList.h185
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ControlFacade.c159
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ControlFacade.h202
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ControlMessage.c245
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ControlMessage.h587
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_Forwarding.c173
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_Forwarding.h242
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ForwardingStrategy.c158
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ForwardingStrategy.h53
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_Interface.c255
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_Interface.h236
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceEthernet.c183
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceEthernet.h243
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceGeneric.c127
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceGeneric.h219
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPMulticast.h179
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnel.c331
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnel.h349
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnelList.c159
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnelList.h204
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceL2Group.h179
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceLocal.h143
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceSet.c210
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceSet.h232
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceType.c102
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_InterfaceType.h98
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_Listener.c432
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_Listener.h427
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ManageCaches.c103
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ManageCaches.h35
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ManageLinks.c188
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ManageLinks.h248
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ManageWldr.c167
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_ManageWldr.h49
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_NameRouteProtocolType.c59
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_NameRouteProtocolType.h95
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_NameRouteType.c64
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_NameRouteType.h92
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_RouteEntry.c466
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_RouteEntry.h587
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_RouteEntryList.c163
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_RouteEntryList.h166
-rw-r--r--libccnx-transport-rta/ccnx/api/control/cpi_private.h60
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/.gitignore24
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/CMakeLists.txt36
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_controlPlaneInterface.c287
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_Acks.c119
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_Address.c550
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_AddressList.c317
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_CancelFlow.c115
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_Connection.c220
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionEthernet.c290
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionList.c186
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlFacade.c220
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlMessage.c378
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_Forwarding.c331
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_Interface.c351
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceEthernet.c191
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceGeneric.c157
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnel.c224
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnelList.c181
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceSet.c243
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceTypes.c91
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_Listener.c384
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_ManageLinks.c266
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_NameRouteType.c93
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_Registration.c72
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntry.c547
-rw-r--r--libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntryList.c177
-rw-r--r--libccnx-transport-rta/ccnx/api/notify/CMakeLists.txt39
-rw-r--r--libccnx-transport-rta/ccnx/api/notify/README20
-rw-r--r--libccnx-transport-rta/ccnx/api/notify/ccnxNotifyAPI_About.c44
-rw-r--r--libccnx-transport-rta/ccnx/api/notify/ccnxNotifyAPI_About.h54
-rw-r--r--libccnx-transport-rta/ccnx/api/notify/notify_Status.c211
-rw-r--r--libccnx-transport-rta/ccnx/api/notify/notify_Status.h345
-rw-r--r--libccnx-transport-rta/ccnx/api/notify/notify_Timer.h18
-rw-r--r--libccnx-transport-rta/ccnx/api/notify/test/.gitignore1
-rw-r--r--libccnx-transport-rta/ccnx/api/notify/test/CMakeLists.txt13
-rw-r--r--libccnx-transport-rta/ccnx/api/notify/test/test_notify_Status.c96
-rw-r--r--libccnx-transport-rta/ccnx/config.h.in4
-rw-r--r--libccnx-transport-rta/ccnx/transport/.gitignore35
-rw-r--r--libccnx-transport-rta/ccnx/transport/CMakeLists.txt216
-rw-r--r--libccnx-transport-rta/ccnx/transport/README24
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/ccnx_ConnectionConfig.c123
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/ccnx_ConnectionConfig.h190
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/ccnx_StackConfig.c160
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/ccnx_StackConfig.h327
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/ccnx_TransportConfig.c120
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/ccnx_TransportConfig.h229
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/test/.gitignore4
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/test/CMakeLists.txt16
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/test/test_ccnx_ConnectionConfig.c183
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/test/test_ccnx_StackConfig.c226
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/test/test_ccnx_TransportConfig.c226
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/test/test_transport.c136
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/test/test_transport_Message.c15
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/test/test_transport_MetaMessage.c283
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/test/test_transport_Stack.c191
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/transport.c123
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/transport.h262
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/transport_Message.c198
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/transport_Message.h175
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/transport_MetaMessage.c193
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/transport_MetaMessage.h515
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/transport_Stack.c137
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/transport_Stack.h354
-rw-r--r--libccnx-transport-rta/ccnx/transport/common/transport_private.h38
-rw-r--r--libccnx-transport-rta/ccnx/transport/librta_About.c44
-rw-r--r--libccnx-transport-rta/ccnx/transport/librta_About.h54
-rw-r--r--libccnx-transport-rta/ccnx/transport/test_tools/bent_pipe.c850
-rw-r--r--libccnx-transport-rta/ccnx/transport/test_tools/bent_pipe.h148
-rw-r--r--libccnx-transport-rta/ccnx/transport/test_tools/ethersend.c211
-rw-r--r--libccnx-transport-rta/ccnx/transport/test_tools/pktgen.c195
-rw-r--r--libccnx-transport-rta/ccnx/transport/test_tools/test/.gitignore1
-rw-r--r--libccnx-transport-rta/ccnx/transport/test_tools/test/test_bent_pipe.c397
-rw-r--r--libccnx-transport-rta/ccnx/transport/test_tools/traffic_tools.c292
-rw-r--r--libccnx-transport-rta/ccnx/transport/test_tools/traffic_tools.h284
-rw-r--r--libccnx-transport-rta/ccnx/transport/test_tools/write_packets.c84
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_Command.c365
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_Command.h619
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCloseConnection.c61
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCloseConnection.h145
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCreateProtocolStack.c113
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCreateProtocolStack.h274
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandDestroyProtocolStack.c59
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandDestroyProtocolStack.h141
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandOpenConnection.c96
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandOpenConnection.h219
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandTransmitStatistics.c81
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandTransmitStatistics.h125
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/.gitignore7
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/CMakeLists.txt18
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_Command.c475
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandCloseConnection.c125
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandCreateProtocolStack.c215
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandDestroyProtocolStack.c125
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandOpenConnection.c199
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandTransmitStatistics.c170
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/component_Vegas.c673
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/test/test_component_Vegas.c696
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/test/test_vegas_Session.c672
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/vegas_Session.c1379
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/vegas_private.h222
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/codec_Signing.c80
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/codec_Signing.h46
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Codec.h28
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Codec_Tlv.c319
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Flowcontrol.h29
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Testing.c45
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Testing.h41
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/test/CMakeLists.txt16
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_codec_Signing.c61
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_component_Codec_Tlv.c276
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_component_Codec_Tlv_Hmac.c204
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_component_Testing.c82
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/components/test/testrig_MockFramework.c99
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_All.h45
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ApiConnector.c52
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ApiConnector.h89
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Codec_Ccnb.xc31
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Codec_Tlv.c62
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Codec_Tlv.h92
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_CryptoCache.h41
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_FlowControl_Vegas.c50
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_FlowControl_Vegas.h92
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Local.c72
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Local.h102
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Metis.c81
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Metis.h118
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_InMemoryVerifier.c52
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_InMemoryVerifier.h81
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ProtocolStack.c121
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ProtocolStack.h114
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_PublicKeySigner.c106
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_PublicKeySigner.h112
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Signer.c65
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Signer.h51
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_SymmetricKeySigner.c95
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_SymmetricKeySigner.h103
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_TestingComponent.c73
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/config_TestingComponent.h137
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/test/CMakeLists.txt22
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_ApiConnector.c141
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Codec_Tlv.c154
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_FlowControl_Vegas.c141
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Forwarder_Local.c152
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Forwarder_Metis.c154
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_InMemoryVerifier.c122
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_ProtocolStack.c167
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_PublicKeySigner.c133
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Signer.c141
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_SymmetricKeySigner.c135
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_TestingComponent.c186
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/config/test/testrig_RtaConfigCommon.c66
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Api.c264
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Api.h22
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Forwarder.h30
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Forwarder_Local.c552
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Forwarder_Metis.c1712
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/connectors/rta_ApiConnection.c634
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/connectors/rta_ApiConnection.h83
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/CMakeLists.txt16
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_connector_Api.c61
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_connector_Forwarder_Local.c249
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_connector_Forwarder_Metis.c1350
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_rta_ApiConnection.c278
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/components.h56
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta.h29
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Component.c127
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Component.h258
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ComponentQueue.h30
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ComponentStats.c124
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ComponentStats.h172
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Connection.c383
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Connection.h457
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ConnectionTable.c250
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ConnectionTable.h109
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework.c469
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework.h181
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Commands.c450
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Commands.h53
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.c204
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.h79
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Services.c44
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Services.h125
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Threaded.c170
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Threaded.h56
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_private.h163
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Logger.c188
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Logger.h227
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ProtocolStack.c786
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ProtocolStack.h379
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/.gitignore10
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/CMakeLists.txt23
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Component.c247
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ComponentStats.c189
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Connection.c82
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ConnectionTable.c309
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework.c298
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_Commands.c449
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_NonThreaded.c83
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_Services.c84
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_Threaded.c83
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Logger.c222
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ProtocolStack.c81
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_WebService.c301
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/rta_Transport.c543
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/rta_Transport.h101
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/test/.gitignore19
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/test/CMakeLists.txt13
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/test/README17
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/test/test_multi_connections.c424
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Commands.c381
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Transport.c701
-rw-r--r--libccnx-transport-rta/cmake/Modules/FindCCNX_Common.cmake39
-rw-r--r--libccnx-transport-rta/cmake/Modules/FindLibEvent.cmake47
-rw-r--r--libccnx-transport-rta/cmake/Modules/FindLibparc.cmake39
-rw-r--r--libccnx-transport-rta/cmake/Modules/FindLongBow.cmake44
-rw-r--r--libccnx-transport-rta/cmake/Modules/FindUncrustify.cmake8
-rw-r--r--libccnx-transport-rta/cmake/Modules/detectCacheSize.cmake21
-rw-r--r--libccnx-transport-rta/cmake/Modules/version.cmake15
-rwxr-xr-xlibccnx-transport-rta/cmake/get_version.sh20
-rw-r--r--libccnx-transport-rta/documentation/.gitignore9
-rw-r--r--libccnx-transport-rta/documentation/Makefile.am91
-rw-r--r--libccnx-transport-rta/documentation/Makefile.notautomake76
-rw-r--r--libccnx-transport-rta/documentation/doxygen-libccnx_api_control.logcd0
-rw-r--r--libccnx-transport-rta/documentation/libccnx-stage1.doxygen2425
-rw-r--r--libccnx-transport-rta/documentation/libccnx-stage2.doxygen2426
-rw-r--r--libccnx-transport-rta/documentation/libccnx_api_control-stage1.doxygen2424
-rw-r--r--libccnx-transport-rta/documentation/libccnx_api_control-stage2.doxygen2422
-rw-r--r--libccnx-transport-rta/documentation/libccnx_api_notify-stage1.doxygen2422
-rw-r--r--libccnx-transport-rta/documentation/libccnx_api_notify-stage2.doxygen2418
-rw-r--r--libccnx-transport-rta/documentation/libccnx_api_portal-stage1.doxygen2424
-rw-r--r--libccnx-transport-rta/documentation/libccnx_api_portal-stage2.doxygen2421
-rw-r--r--libccnx-transport-rta/documentation/librta-stage1.doxygen2415
-rw-r--r--libccnx-transport-rta/documentation/librta-stage2.doxygen2418
-rw-r--r--libccnx-transport-rta/documentation/stylesheet.css47
675 files changed, 197907 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;
+}
diff --git a/libccnx-portal/.gitignore b/libccnx-portal/.gitignore
new file mode 100644
index 00000000..6a21e78b
--- /dev/null
+++ b/libccnx-portal/.gitignore
@@ -0,0 +1,98 @@
+VERSION
+.cproject
+.project
+*.plist
+libccnx*.tar.gz
+
+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
+.DS_Store
+
+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-portal/AUTHORS b/libccnx-portal/AUTHORS
new file mode 100644
index 00000000..d0ae0f66
--- /dev/null
+++ b/libccnx-portal/AUTHORS
@@ -0,0 +1,9 @@
+Libccnx-common authors are listed below
+
+ Michele Papalini <micpapal@cisco.com>
+ Glenn Scott <Glenn.Scott@parc.com>
+ Alan Walendowski <Alan.Walendowski@parc.com>
+
+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-portal/BASE_VERSION b/libccnx-portal/BASE_VERSION
new file mode 100644
index 00000000..d3827e75
--- /dev/null
+++ b/libccnx-portal/BASE_VERSION
@@ -0,0 +1 @@
+1.0
diff --git a/libccnx-portal/CMakeLists.txt b/libccnx-portal/CMakeLists.txt
new file mode 100644
index 00000000..5c528df3
--- /dev/null
+++ b/libccnx-portal/CMakeLists.txt
@@ -0,0 +1,89 @@
+cmake_minimum_required(VERSION 3.2)
+project(Libccnx-portal)
+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)
+
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+if( UNIX )
+ link_libraries(m)
+endif( UNIX )
+
+include( CTest )
+include( version )
+include( detectCacheSize )
+
+if(ANDROID_API)
+ message("############ Detected cross compile for $ENV{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_Portal_DISABLE_VALIDATION")
+ find_package( Doxygen )
+endif()
+#set(CMAKE_C_FLAGS_NOPANTS "${CMAKE_C_FLAGS_NOPANTS} -O3 -DNDEBUG -DLibccnx_Portal_DISABLE_VALIDATION")
+
+include_directories(${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR}/ccnx/api/ccnx_Portal)
+
+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( CCNX_Common REQUIRED )
+include_directories(${CCNX_COMMON_INCLUDE_DIRS})
+
+find_package( CCNX_Transport_Rta REQUIRED )
+include_directories(${CCNX_TRANSPORT_RTA_INCLUDE_DIRS})
+
+find_package ( Threads REQUIRED )
+
+find_package ( OpenSSL REQUIRED )
+
+
+
+set(CCNX_LINK_LIBRARIES
+ ${LONGBOW_LIBRARIES}
+ ${LIBEVENT_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ccnx_api_portal
+ ${CCNX_TRANSPORT_RTA_LIBRARIES}
+ ${CCNX_COMMON_LIBRARIES}
+ ${LIBPARC_LIBRARIES}
+ )
+
+set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
+
+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} ${CCNX_LINK_LIBRARIES})
+ add_test(${ARGV0} ${ARGV0})
+ set_target_properties(${ARGV0} PROPERTIES FOLDER Test)
+ endmacro(AddTest)
+endif()
+
+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_subdirectory(ccnx/api/ccnx_Portal)
+add_subdirectory(documentation)
diff --git a/libccnx-portal/LICENSE b/libccnx-portal/LICENSE
new file mode 100644
index 00000000..99c77d9d
--- /dev/null
+++ b/libccnx-portal/LICENSE
@@ -0,0 +1,14 @@
+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-portal/README.md b/libccnx-portal/README.md
new file mode 100644
index 00000000..7052d8fd
--- /dev/null
+++ b/libccnx-portal/README.md
@@ -0,0 +1,82 @@
+Libccnx-portal
+=======
+A CCNx base API
+
+## Quick Start ##
+
+$ git clone -b ccnxlibs/master https://gerrit.fd.io/r/cicn ccnxlibs
+$ cd ccnxlibs/libccnx-portal
+$ mkdir build
+$ cd build
+$ cmake ..
+$ make
+$ make test
+$ make install
+```
+
+## Introduction ##
+
+The CCNx Portal API is a simple API to communicate via Interests and Content Objects. It connects to a transport stack like Transport RTA (libccnx-transport-rta).
+
+## Using Libccnx-portal ##
+
+### Platforms ###
+
+Libccnx-portal 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
+- libccnx-common
+- libccnx-transport-rta
+
+
+Documentation dependencies:
+
+- Doxygen
+
+
+### Using Libccnx-portal ###
+
+Libccnx-portal 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_api_portal library.
+
+```
+CCNX_HOME=<directory-where-Libccnx-portal-is-installed>
+
+-I${CCNX_HOME}/include -L${CCNX_HOME}/lib -lccnx_api_portal
+```
+
+### 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-portal/ccnx/api/ccnx_Portal/CMakeLists.txt b/libccnx-portal/ccnx/api/ccnx_Portal/CMakeLists.txt
new file mode 100644
index 00000000..b4d2a136
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/CMakeLists.txt
@@ -0,0 +1,52 @@
+# Define a few configuration variables that we want accessible in the software
+
+configure_file(config.h.in config.h @ONLY)
+
+set(CCNX_API_PORTAL_HEADERS
+ ccnx_Portal.h
+ ccnx_PortalFactory.h
+ ccnx_PortalAttributes.h
+ ccnx_PortalStack.h
+ ccnx_PortalRTA.h
+ ccnx_PortalAPI.h
+ ccnx_PortalAnchor.h
+ ccnxPortal_About.h
+ )
+
+set(CCNX_API_PORTAL_SOURCE_FILES
+ ${CCNX_API_PORTAL_HEADERS}
+ ccnx_Portal.c
+ ccnx_PortalFactory.c
+ ccnx_PortalAttributes.c
+ ccnx_PortalStack.c
+ ccnx_PortalRTA.c
+ ccnx_PortalAPI.c
+ ccnx_PortalAnchor.c
+ ccnxPortal_About.c
+ )
+
+source_group(Sources FILES ${CCNX_API_PORTAL_SOURCE_FILES})
+source_group(Sources FILES ${CCNX_API_PORTAL_HEADERS})
+
+add_library(ccnx_api_portal STATIC ${CCNX_API_PORTAL_SOURCE_FILES} ${CCNX_API_PORTAL_HEADER_FILES})
+add_library(ccnx_api_portal.shared SHARED ${CCNX_API_PORTAL_SOURCE_FILES})
+set_target_properties(ccnx_api_portal.shared PROPERTIES
+ C_STANDARD 99
+ SOVERSION 1
+ VERSION 1.0
+ OUTPUT_NAME ccnx_api_portal )
+
+set(libccnx_api_portal_libraries
+ ccnx_api_portal
+ ccnx_api_portal.shared
+ )
+
+foreach(lib ${libccnx_api_portal_libraries})
+ install(TARGETS ${lib} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
+ set_property(TARGET ${lib} PROPERTY C_STANDARD 99)
+endforeach()
+
+install(FILES ${CCNX_API_PORTAL_HEADERS} DESTINATION include/ccnx/api/ccnx_Portal )
+
+add_subdirectory(test)
+add_subdirectory(command-line)
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.c
new file mode 100644
index 00000000..a942db2c
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T10:25:45Z
+
+#include "ccnxPortal_About.h"
+
+const char *ccnxPortal_What = "@(#)" "CCNx Portal API " RELEASE_VERSION " 2017-02-22T13:18:15.247445"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+ccnxPortalAbout_Name(void)
+{
+ return "CCNx Portal API";
+}
+
+const char *
+ccnxPortalAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+ccnxPortalAbout_About(void)
+{
+ return "CCNx Portal API "RELEASE_VERSION " 2017-02-22T13:18:15.247445" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalAbout_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-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.h
new file mode 100755
index 00000000..47c6651f
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnxPortal_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T10:25:45Z
+
+#ifndef ccnxPortal_About_h
+#define ccnxPortal_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *ccnxPortal_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *ccnxPortalAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *ccnxPortalAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *ccnxPortalAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *ccnxPortalAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *ccnxPortalAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *ccnxPortalAbout_LongNotice(void);
+
+#endif // ccnxPortal_About_h
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.c
new file mode 100755
index 00000000..94e36086
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.c
@@ -0,0 +1,257 @@
+/*
+ * 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 <pthread.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAnchor.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <ccnx/api/control/controlPlaneInterface.h>
+
+#include <ccnx/transport/common/transport.h>
+
+struct ccnx_portal_status {
+ int error;
+ bool eof;
+};
+
+struct ccnx_portal {
+ CCNxPortalStatus status;
+
+ const CCNxPortalStack *stack;
+};
+
+static CCNxMetaMessage *
+_ccnxPortal_ComposeAnchorMessage(const CCNxName *routerName, const CCNxName *name, int secondsToLive)
+{
+ time_t expireTime = time(0) + secondsToLive;
+ CCNxPortalAnchor *namePrefix = ccnxPortalAnchor_Create(name, expireTime);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ ccnxPortalAnchor_Serialize(namePrefix, composer);
+ PARCBuffer *payload = parcBufferComposer_ProduceBuffer(composer);
+
+ CCNxInterest *interest = ccnxInterest_CreateSimple(routerName);
+ ccnxInterest_SetPayload(interest, payload);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+
+ parcBuffer_Release(&payload);
+ ccnxInterest_Release(&interest);
+ parcBufferComposer_Release(&composer);
+ ccnxPortalAnchor_Release(&namePrefix);
+
+ return message;
+}
+
+static int
+_ccnxPortal_SetAnchor(CCNxPortal *portal, const CCNxName *name, time_t secondsToLive)
+{
+ int64_t timeOutMicroSeconds = parcProperties_GetAsInteger(ccnxPortalStack_GetProperties(portal->stack), CCNxPortalFactory_LocalRouterTimeout, 1000000);
+
+ CCNxName *routerName = ccnxName_CreateFromCString(ccnxPortalStack_GetProperty(portal->stack, CCNxPortalFactory_LocalRouterName, "lci:/local/dcr"));
+ CCNxName *fullName = ccnxName_ComposeNAME(routerName, "anchor");
+
+ CCNxMetaMessage *message = _ccnxPortal_ComposeAnchorMessage(fullName, name, secondsToLive);
+
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_MicroSeconds(timeOutMicroSeconds));
+ ccnxMetaMessage_Release(&message);
+
+ CCNxMetaMessage *response = ccnxPortal_Receive(portal, CCNxStackTimeout_MicroSeconds(timeOutMicroSeconds));
+ if (response != NULL) {
+ ccnxMetaMessage_Release(&response);
+ }
+
+ ccnxName_Release(&fullName);
+ ccnxName_Release(&routerName);
+
+ return 0;
+}
+
+bool
+ccnxPortal_Flush(CCNxPortal *portal, const CCNxStackTimeout *timeout)
+{
+ CCNxControl *control = ccnxControl_CreateFlushRequest();
+
+ // this needs to be better wrapped in ccnxControl
+ PARCJSON *json = ccnxControl_GetJson(control);
+ uint64_t expectedSequenceNumber = controlPlaneInterface_GetSequenceNumber(json);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromControl(control);
+ bool result = ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+
+ ccnxMetaMessage_Release(&message);
+ ccnxControl_Release(&control);
+
+ if (result == true) {
+ bool matchedSequenceNumber = false;
+ while (!matchedSequenceNumber) {
+ message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ if (message) {
+ if (ccnxMetaMessage_IsControl(message)) {
+ control = ccnxMetaMessage_GetControl(message);
+ if (ccnxControl_IsCPI(control) && ccnxControl_IsACK(control)) {
+ uint64_t sequenceNumber = ccnxControl_GetAckOriginalSequenceNumber(control);
+ if (sequenceNumber == expectedSequenceNumber) {
+ matchedSequenceNumber = true;
+ }
+ }
+ }
+ ccnxMetaMessage_Release(&message);
+ } else {
+ // this is likely some sort of error with the connection.
+ // should report this somehow. This case shows up from test_ccnx_PortalAPI.
+ result = false;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+static void
+_ccnxPortal_Destroy(CCNxPortal **portalPtr)
+{
+ CCNxPortal *portal = *portalPtr;
+
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+
+ ccnxPortalStack_Stop(portal->stack);
+ ccnxPortalStack_Release((CCNxPortalStack **) &portal->stack);
+}
+
+parcObject_ExtendPARCObject(CCNxPortal, _ccnxPortal_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(ccnxPortal, CCNxPortal);
+
+parcObject_ImplementRelease(ccnxPortal, CCNxPortal);
+
+CCNxPortal *
+ccnxPortal_Create(const CCNxPortalAttributes *attributes, const CCNxPortalStack *portalStack)
+{
+ CCNxPortal *result = parcObject_CreateInstance(CCNxPortal);
+
+ if (result != NULL) {
+ result->stack = portalStack;
+ result->status.eof = false;
+ result->status.error = 0;
+ }
+
+ if (ccnxPortalStack_Start(portalStack) == false) {
+ parcObject_Release((void **) &result);
+ }
+
+ return result;
+}
+
+const CCNxPortalStatus *
+ccnxPortal_GetStatus(const CCNxPortal *portal)
+{
+ return &portal->status;
+}
+
+bool
+ccnxPortal_SetAttributes(CCNxPortal *portal, const CCNxPortalAttributes *attributes)
+{
+ return ccnxPortalStack_SetAttributes(portal->stack, attributes);
+}
+
+int
+ccnxPortal_GetFileId(const CCNxPortal *portal)
+{
+ return ccnxPortalStack_GetFileId(portal->stack);
+}
+
+bool
+ccnxPortal_Listen(CCNxPortal *restrict portal, const CCNxName *restrict name, const time_t secondsToLive, const CCNxStackTimeout *microSeconds)
+{
+ bool result = ccnxPortalStack_Listen(portal->stack, name, microSeconds);
+
+ if (result == true) {
+ _ccnxPortal_SetAnchor(portal, name, secondsToLive);
+ }
+
+ portal->status.error = (result == true) ? 0 : ccnxPortalStack_GetErrorCode(portal->stack);
+
+ return result;
+}
+
+bool
+ccnxPortal_Ignore(CCNxPortal *portal, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ bool result = ccnxPortalStack_Ignore(portal->stack, name, microSeconds);
+
+ portal->status.error = (result == true) ? 0 : ccnxPortalStack_GetErrorCode(portal->stack);
+
+ return result;
+}
+
+bool
+ccnxPortal_Send(CCNxPortal *restrict portal, const CCNxMetaMessage *restrict message, const CCNxStackTimeout *timeout)
+{
+ bool result = ccnxPortalStack_Send(portal->stack, message, timeout);
+
+ portal->status.error = result ? 0 : ccnxPortalStack_GetErrorCode(portal->stack);
+ return result;
+}
+
+CCNxMetaMessage *
+ccnxPortal_Receive(CCNxPortal *portal, const CCNxStackTimeout *timeout)
+{
+ CCNxMetaMessage *result = ccnxPortalStack_Receive(portal->stack, timeout);
+
+ // This modal operation of Portal is awkward.
+ // Messages are interest = content-object, while Chunked is interest = {content-object_1, content-object_2, ...}
+ // If chunked.
+ // If Content Object
+ // If this content object is the final chunk
+ // Set EOF
+
+ portal->status.error = (result != NULL) ? 0 : ccnxPortalStack_GetErrorCode(portal->stack);
+ return result;
+}
+
+const PARCKeyId *
+ccnxPortal_GetKeyId(const CCNxPortal *portal)
+{
+ return ccnxPortalStack_GetKeyId(portal->stack);
+}
+
+bool
+ccnxPortal_IsEOF(const CCNxPortal *portal)
+{
+ return portal->status.eof;
+}
+
+bool
+ccnxPortal_IsError(const CCNxPortal *portal)
+{
+ return portal->status.error != 0;
+}
+
+int
+ccnxPortal_GetError(const CCNxPortal *portal)
+{
+ return portal->status.error;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.h
new file mode 100644
index 00000000..59711d0f
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_Portal.h
@@ -0,0 +1,529 @@
+/*
+ * 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_Portal.h
+ * @brief A low-level API for CCN Interests, Content Objects, and Control messages.
+ *
+ * \mainpage CCNxPortal
+ * CCNxPortal is a low-level API providing direct access to individual CCNxInterest and CCNxContentObject messages.
+ * The API provides very basic access to the "registration" operations for applications to receive CCNxInterest messages and
+ * facilities for using different, pre-configured protocol stacks.
+ *
+ * An application may have many `CCNxPortal` instances, each instance representing a particular protocol stack configuration.
+ * Normally an application uses a `CCNxPortalFactory`to create instances rather than creating `CCNxPortal` instances directly.
+ * This permits a factory to be setup to provide common attributes and configuration parameters shared by multiple `CCNxPortal`
+ * instances.
+ *
+ * The input/output functions, whether direct like `ccnxPortal_Send` and `ccnxPortal_Receive`,
+ * in indirect (such as `ccnxPortal_Listen`), take a parameter that specifiess a timeout behaviour for the function.
+ * As a result, an application may use the functions as blocking or non-blocking I/O as needed without having to use
+ * multiple `CCNxPortal` instances with different blocking or non-blocking behaviour.
+ *
+ * Specifying the timeout behaviour consists of providing a pointer to a `CCNxStackTimeout` value,
+ * or the value `CCNxStackTimeout_Never`.
+ *
+ * * `CCNxStackTimeout_Immediate`:
+ * The function returns immediately,
+ * after first attempting to perform its function provided it can complete without any blocking.
+ * For example `ccnxPortal_Receive` will return either the next `CCNxMetaMessage`,
+ * if one is waiting, or NULL indicating no message was available.
+ * The function `ccnxPortal_Send` will return after first attempting to enqueue its message on the output message queue.
+ * If the function would have to wait for space on the output message queue, then it returns indicating failure.
+ *
+ * * `CCNxStackTimeout_Microseconds()`:
+ * Functions will perform their operations blocking only for the maximum time
+ * specified.
+ *
+ * * `CCNxStackTimeout_Never`:
+ * Functions will perform their operations potentially blocking forever.
+ *
+ */
+#ifndef CCNx_Portal_API_ccnx_Portal_h
+#define CCNx_Portal_API_ccnx_Portal_h
+
+struct ccnx_portal_status;
+/**
+ * @brief The status of the CCNx Portal
+ */
+typedef struct ccnx_portal_status CCNxPortalStatus;
+
+struct ccnx_portal;
+/**
+ * @brief The CCNx Portal
+ */
+typedef struct ccnx_portal CCNxPortal;
+
+#include <parc/security/parc_Identity.h>
+#include <parc/security/parc_KeyId.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAttributes.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalFactory.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalStack.h>
+
+#include <ccnx/common/ccnx_Interest.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+
+/**
+ * Create a new `CCNxPortal` instance with the given {@link CCNxPortalStack}.
+ *
+ * @param [in] attributes A pointer to a valid `CCNxPortalAttributes` instance
+ * @param [in] stack A pointer to a valid `CCNxPortalStack` instance.
+ *
+ * @return non-NULL A pointer to a valid `CCNxPortal` instance that must be released via {@link ccnxPortal_Release}.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxPortal *ccnxPortal_Create(const CCNxPortalAttributes *attributes, const CCNxPortalStack *stack);
+
+/**
+ * Increase the number of references to a `CCNxPortal`.
+ *
+ * Note that new `CCNxPortal` is not created,
+ * only that the given `CCNxPortal` reference count is incremented.
+ * Discard the reference by invoking `parcBuffer_Release`.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ * @return The input `CCNxPortal` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortal_Create(attributes, stack);
+ *
+ * CCNxPortal *portal2 = ccnxPortal_Acquire(portal);
+ *
+ * ccnxPortal_Release(&portal);
+ * ccnxPortal_Release(&portal2);
+ * }
+ * @endcode
+ */
+CCNxPortal *ccnxPortal_Acquire(const CCNxPortal *portal);
+
+/**
+ * Release a previously acquired reference to the specified `CCNxPortal` 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] portalPtr A pointer to a pointer to a `CCNxPortal` instance to be released.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortalFactory_CreatePortal}
+ * @see {@link ccnxPortal_Create}
+ */
+void ccnxPortal_Release(CCNxPortal **portalPtr);
+
+/**
+ * Return a pointer to the given `CCNxPortal`'s {@link CCNxPortalStatus} instance.
+ *
+ * A `CCNxPortalStatus` instance is used to extract information about the state of the open
+ * portal, e.g., whether or not an error has occurred or EOF has been reached.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ *
+ * @return A non-null pointer to a `CCNxPortalStatus` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * CCNxPortalStatus *status = ccnxPortal_GetStatus(portal);
+ *
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ */
+const CCNxPortalStatus *ccnxPortal_GetStatus(const CCNxPortal *portal);
+
+/**
+ * Get the underlying file descriptor for the given `CCNxPortal`.
+ *
+ * This is the operating systems file descriptor for use with read, write, close, select, poll, ioctl, and so forth.
+ *
+ * @b Users should expect that this function will be removed in favor
+ * of a more general select/poll implementation that works with instances of `CCNxPortal` as well as normal file descriptors.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ *
+ * @return The underlying file descriptor for the given `CCNxPortal`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * int fileDescriptor = ccnxPortal_GetFile(portal);
+ *
+ * // use the fileDescriptor as necessary
+ *
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ */
+int ccnxPortal_GetFileId(const CCNxPortal *portal);
+
+/**
+ * Set the attributes for the specified `CCNxPortal` instance.
+ *
+ * A {@link CCNxPortalAttributes} instance encapsulates information about the logging and blocked
+ * state of the `CCNxPortal` instance. These are immutable instances which are not
+ * meant to be changed. Rather, they are intended to configure the attributes
+ * of other `CCNxPortal` instances.
+ *
+ * @param [in,out] portal A pointer to a `CCNxPortal` instance.
+ * @param [in] attributes A pointer to a `CCNxPortalAttributes` instance that will be used.
+ *
+ * @return `true` if the attributes were successfully set, `false` otherwise.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_GetAttributes}
+ */
+bool ccnxPortal_SetAttributes(CCNxPortal *portal, const CCNxPortalAttributes *attributes);
+
+/**
+ * Listen for CCN Interests in the given {@link CCNxName}, i.e., with the given name prefix.
+ *
+ * If the local CCN router is available, this induces a route update for the given name.
+ * Messaging with the local CCN router are governed by the `CCNxPortalFactory` properties named by `CCNxPortalFactory_LocalRouterTimeout`
+ *
+ * An invocation of the function will return after the time specified by the `CCNxStackTimeout` value,
+ * or the function will potentially wait forever if the value is `CCNxStackTimeout_Never`
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ * @param [in] name A `CCNxName` prefix used to filter and accept Interests.
+ * @param [in] secondsToLive The number of seconds for this Listen to remain active.
+ * @param [in] timeout A pointer to a `CCNxStackTimeout` value, or `CCNxStackTimeout_Never`.
+ *
+ * @return `true` The operation succeeded.
+ * @return `false` The operation failed. See {@link ccnxPortal_GetStatus}.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ * const char *uri = "lci:/PARC";
+ * CCNxName *name = ccnxName_CreateFromCString(reguri);
+ *
+ * if (ccnxPortal_Listen(portal, name, 600, CCNxStackTimeout_MicroSeconds(5000))) {
+ * ...
+ * }
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_Ignore}
+ * @see {@link ccnxPortalFactory_CreatePortal}
+ */
+bool ccnxPortal_Listen(CCNxPortal *restrict portal, const CCNxName *restrict name, const time_t secondsToLive, const CCNxStackTimeout *timeout);
+
+/**
+ * Stop listening for Interests with the given {@link CCNxName}.
+ *
+ * An invocation of the function will return after the time specified by the `CCNxStackTimeout` value,
+ * or the function will potentially wait forever if the value is `CCNxStackTimeout_Never`
+ *
+ * @param [in,out] portal A pointer to a `CCNxPortal` instance.
+ * @param [in] name A `CCNxName` name to be ignored.
+ * @param [in] timeout A pointer to a `CCNxStackTimeout` value, or `CCNxStackTimeout_Never`.
+ *
+ * @return `true` The operation succeeded
+ * @return `false` The operation failed. See {@link CCNxPortalStatus}.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ * const char *uri = "lci:/PARC";
+ * CCNxName *name = ccnxName_CreateFromCString(reguri);
+ *
+ * if (ccnxPortal_Listen(portal, name, 86400, CCNxStackTimeout_Never)) {
+ * ...
+ * if (ccnxPortal_Ignore(portal, name, CCNxStackTimeout_Never)) {
+ * ....
+ * }
+ * }
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_Listen}
+ * @see {@link CCNxPortalStatus}
+ */
+bool ccnxPortal_Ignore(CCNxPortal *portal, const CCNxName *name, const CCNxStackTimeout *timeout);
+
+/**
+ * Send a {@link CCNxMetaMessage} to the protocol stack.
+ *
+ * The portal message may be an Interest, Content Object, or Control Message.
+ * The exact type wrapped by the portal message may be determined via
+ * {@link ccnxMetaMessage_IsInterest}, {@link ccnxMetaMessage_IsContentObject}, and
+ * {@link ccnxMetaMessage_IsControl}. This enables a seamless API for both
+ * both producer and consumer applications.
+ *
+ * An invocation of the function will wait for the time specified by the pointer to the `CCNxStackTimeout` value,
+ * or the function will potentially wait forever if the value is `CCNxStackTimeout_Never`.
+ *
+ * @param [in,out] portal A pointer to a `CCNxPortal` instance.
+ * @param [in] message A pointer to a `CCNxMetaMessage` instance.
+ * @param [in] timeout A pointer to a `CCNxStackTimeout` value, or `CCNxStackTimeout_Never`.
+ *
+ * @return `true` No errors occurred.
+ * @return `false` A protocol stack error occurred while writing the message (see `ccnxPortal_GetError`).
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+ *
+ * if (ccnxPortal_Send(portal, message, CCNxStackTimeout_Never)) {
+ * ...
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * ccnxInterest_Release(&interest);
+ * ccnxName_Release(&name);
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_Receive}
+ */
+bool ccnxPortal_Send(CCNxPortal *restrict portal, const CCNxMetaMessage *restrict message, const CCNxStackTimeout *timeout);
+
+/**
+ * Read data from the protocol stack and construct a {@link CCNxMetaMessage}.
+ *
+ * The portal message may be an Interest, Content Object, or Control Message.
+ * The exact type wrapped by the portal message may be determined via
+ * {@link ccnxMetaMessage_IsInterest}, {@link ccnxMetaMessage_IsContentObject}, and
+ * {@link ccnxMetaMessage_IsControl}. This enables a seamless API for both
+ * both producer and consumer applications.
+ *
+ * An invocation of the function will wait for the time specified by the pointer to the `CCNxStackTimeout` value,
+ * or the function will potentially wait forever if the value is `CCNxStackTimeout_Never`.
+ *
+ * If NULL is returned, the caller may test the value of `errno` to discriminate the conditions.
+ *
+ * @param [in,out] portal A pointer to a `CCNxPortal` instance.
+ * @param [in] timeout A pointer to a `CCNxStackTimeout` value, or `CCNxStackTimeout_Never`.
+ *
+ * @return CCNxMetaMessage A `CCNxMetaMessage` instance that must be freed via {@link ccnxMetaMessage_Release}.
+ * @return NULL An error occurred while reading from the protocol stack (see `ccnxPortal_GetError`).
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ * CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ *
+ * CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+ *
+ * if (ccnxPortal_Send(portal, message, CCNxStackTimeout_Never)) {
+ * for (int responses = 0; responses == 0;) {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ * if (message != NULL) {
+ * ...
+ * }
+ * }
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * ccnxInterest_Release(&interest);
+ * ccnxName_Release(&name);
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_Send}
+ * @see `ccnxMetaMessage_IsInterest`
+ * @see `ccnxMetaMessage_IsContentObject`
+ * @see `ccnxMetaMessage_IsControl`
+ */
+CCNxMetaMessage *ccnxPortal_Receive(CCNxPortal *portal, const CCNxStackTimeout *timeout);
+
+/**
+ * Get the {@link PARCKeyId} of the identity bound to the given `CCNxPortal` instance.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ *
+ * @return The `PARCKeyId` instance associated with this `CCNxPortal`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal =
+ * ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * PARCKeyId *keyId = ccnxPortal_GetKeyId(portal);
+ *
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see ccnxPortalFactory_CreatePortal
+ */
+const PARCKeyId *ccnxPortal_GetKeyId(const CCNxPortal *portal);
+
+/**
+ * Return `true` if the last operation induced an end-of-file state.
+ *
+ * <b>Currently this is inoperable. It's likely that the chunked mode of Portal will be deprecated and replaced at a high archtectural level.</b>
+ *
+ * This only applies to Portal instances configured for Chunked protocol.
+ * If the received chunk is equal to the currently `last chunk` this will return true.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ *
+ * @return `true` The last operation induced an end-of-file state.
+ * @return `false` The last operation did not induce an end-of-file state.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Chunked);
+ *
+ * const char *uri = "lci:/PARC";
+ * CCNxName *name = ccnxName_CreateFromCString(reguri);
+ *
+ * if (ccnxPortal_Listen(portal, name, 86400, CCNxStackTimeout_Never)) {
+ * ...
+ *
+ * bool isEOF = ccnxPortal_IsEOF(portal);
+ * ...
+ * }
+ *
+ * ccnxName_Release(&name);
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ */
+bool ccnxPortal_IsEOF(const CCNxPortal *portal);
+
+/**
+ * Return `true` if the last operation induced an error, `false` otherwise.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ *
+ * @return `true` The last operation induced an error.
+ * @return `false` The last operation induced no error.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * const char *uri = "lci:/PARC";
+ * CCNxName *name = ccnxName_CreateFromCString(reguri);
+ *
+ * if (ccnxPortal_Listen(portal, name, 86400, CCNxStackTimeout_Never)) {
+ * ...
+ *
+ * bool isError = ccnxPortal_IsError(portal);
+ * ...
+ * }
+ *
+ * ccnxName_Release(&name);
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_GetError}
+ */
+bool ccnxPortal_IsError(const CCNxPortal *portal);
+
+/**
+ * Determine the type of error, if any, that has occurred.
+ *
+ * The return value corresponds to the values of errno.
+ *
+ * @param [in] portal A pointer to a `CCNxPortal` instance.
+ *
+ * @return An integer error code.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ *
+ * const char *uri = "lci:/PARC";
+ * CCNxName *name = ccnxName_CreateFromCString(reguri);
+ *
+ * if (ccnxPortal_Listen(portal, name, 86400, CCNxStackTimeout_Never)) {
+ * ...
+ *
+ * bool isError = ccnxPortal_IsError(portal);
+ * if (isError) {
+ * printf("Error code: %d\n", ccnxPortal_GetError(portal));
+ * }
+ *
+ * ...
+ * }
+ *
+ * ccnxName_Release(&name);
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_IsError}
+ */
+int ccnxPortal_GetError(const CCNxPortal *portal);
+
+/**
+ * Flush the input and output paths and pause the protocol stack.
+ *
+ * The timeout value is currently not used, instead this function will block until the operation is complete.
+ *
+ * @param [in] portal A pointer to a valid instance of `CCNxPortal`.
+ * @param [in] timeout A pointer to a `CCNxStackTimeout` value, or `CCNxStackTimeout_Never`.
+ *
+ * @return `true` If successful.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxPortal_Flush(CCNxPortal *portal, const CCNxStackTimeout *timeout);
+
+#endif // CCNx_Portal_API_ccnx_Portal_h
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.c
new file mode 100755
index 00000000..092e063c
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.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 <LongBow/runtime.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAPI.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Deque.h>
+
+typedef struct {
+ PARCDeque *messageAddressBuffer;
+} _CCNxPortalAPIContext;
+
+static void
+_ccnxPortalAPIContext_Destroy(_CCNxPortalAPIContext **instancePtr)
+{
+ _CCNxPortalAPIContext *instance = *instancePtr;
+
+ parcDeque_Release(&instance->messageAddressBuffer);
+}
+
+parcObject_ExtendPARCObject(_CCNxPortalAPIContext, _ccnxPortalAPIContext_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+//static parcObject_ImplementAcquire(_ccnxPortalAPIContext, _CCNxPortalAPIContext);
+
+static parcObject_ImplementRelease(_ccnxPortalAPIContext, _CCNxPortalAPIContext);
+
+static _CCNxPortalAPIContext *
+_ccnxPortalAPIContext_Create(void)
+{
+ _CCNxPortalAPIContext *result = parcObject_CreateInstance(_CCNxPortalAPIContext);
+ result->messageAddressBuffer = parcDeque_Create();
+ return result;
+}
+
+static void
+_ccnxPortalAPI_Start(void *privateData)
+{
+}
+
+static void
+_ccnxPortalAPI_Stop(void *privateData)
+{
+}
+
+static bool
+_ccnxPortalAPI_Send(void *privateData, const CCNxMetaMessage *portalMessage, const CCNxStackTimeout *microSeconds)
+{
+ const _CCNxPortalAPIContext *transportContext = (_CCNxPortalAPIContext *) privateData;
+
+ // Save the address of the portal message on our queue. We don't need to copy the whole message.
+ parcDeque_Append(transportContext->messageAddressBuffer, (void *) ccnxMetaMessage_Acquire(portalMessage));
+
+ return true;
+}
+
+static CCNxMetaMessage *
+_ccnxPortalAPI_Receive(void *privateData, const CCNxStackTimeout *microSeconds)
+{
+ const _CCNxPortalAPIContext *transportContext = (_CCNxPortalAPIContext *) privateData;
+
+ if (parcDeque_IsEmpty(transportContext->messageAddressBuffer)) {
+ return NULL;
+ }
+
+ CCNxMetaMessage *result = (CCNxMetaMessage *) parcDeque_RemoveFirst(transportContext->messageAddressBuffer);
+
+ return result;
+}
+
+static int
+_ccnxPortalAPI_GetFileId(void *privateData)
+{
+ return 3;
+}
+
+static CCNxPortalAttributes *
+_ccnxPortalAPI_GetAttributes(void *privateData)
+{
+ return NULL;
+}
+
+static bool
+_ccnxPortalAPI_SetAttributes(void *privateData, const CCNxPortalAttributes *attributes)
+{
+ return false;
+}
+
+static bool
+_ccnxPortalAPI_Listen(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ return true;
+}
+
+static bool
+_ccnxPortalAPI_Ignore(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ return true;
+}
+
+CCNxPortal *
+ccnxPortalAPI_LoopBack(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes)
+{
+ _CCNxPortalAPIContext *apiContext = _ccnxPortalAPIContext_Create();
+
+ CCNxPortalStack *stack =
+ ccnxPortalStack_Create(factory,
+ attributes,
+ _ccnxPortalAPI_Start,
+ _ccnxPortalAPI_Stop,
+ _ccnxPortalAPI_Receive,
+ _ccnxPortalAPI_Send,
+ _ccnxPortalAPI_Listen,
+ _ccnxPortalAPI_Ignore,
+ _ccnxPortalAPI_GetFileId,
+ _ccnxPortalAPI_SetAttributes,
+ _ccnxPortalAPI_GetAttributes,
+ apiContext,
+ (void (*)(void **))_ccnxPortalAPIContext_Release);
+
+ CCNxPortal *result = ccnxPortal_Create(attributes, stack);
+ return result;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.h
new file mode 100755
index 00000000..b5bf0f4c
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAPI.h
@@ -0,0 +1,44 @@
+/*
+ * 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_PortalAPI.h
+ * @brief A Portal Protocol Stack implementation that simulates a real network stack.
+ *
+ * This Portal Protocol Stack implementation simulates a network stack for the purposes of testing and development.
+ *
+ */
+#ifndef __CCNx_Portal_API__ccnxPortalAPI__
+#define __CCNx_Portal_API__ccnxPortalAPI__
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAttributes.h>
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+
+/**
+ * Create a {@link CCNxPortal} instance from the given @p factory and @p attributes.
+ *
+ * @param [in] factory A pointer to a valid {@link CCNxPortalFactory} instance
+ * @param [in] attributes A pointer to a valid {@link CCNxPortalAttributes} instance
+ *
+ * @return non-null A pointer to a valid `CCNxPortal` instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxPortal *ccnxPortalAPI_LoopBack(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes);
+
+#endif /* defined(__CCNx_Portal_API__ccnxPortalAPI__) */
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.c
new file mode 100644
index 00000000..3155823a
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.c
@@ -0,0 +1,258 @@
+/*
+ * 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_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Time.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAnchor.h>
+
+struct CCNxPortalAnchor {
+ CCNxName *prefix;
+ time_t expireTime;
+};
+
+static bool
+_ccnxPortalAnchor_Destructor(CCNxPortalAnchor **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a CCNxPortalAnchor pointer.");
+ CCNxPortalAnchor *instance = *instancePtr;
+
+ ccnxName_Release(&instance->prefix);
+
+ /* cleanup the instance fields here */
+ return true;
+}
+
+parcObject_ImplementAcquire(ccnxPortalAnchor, CCNxPortalAnchor);
+
+parcObject_ImplementRelease(ccnxPortalAnchor, CCNxPortalAnchor);
+
+#define parcObject_OverrideCopy(_name_) .copy = (PARCObjectCopy *) _name_
+parcObject_Override(CCNxPortalAnchor, PARCObject,
+ parcObject_OverrideCopy(ccnxPortalAnchor_Copy),
+ .toString = (PARCObjectToString *) ccnxPortalAnchor_ToString,
+ .equals = (PARCObjectEquals *) ccnxPortalAnchor_Equals,
+ .compare = (PARCObjectCompare *) ccnxPortalAnchor_Compare,
+ .hashCode = (PARCObjectHashCode *) ccnxPortalAnchor_HashCode,
+ .toJSON = (PARCObjectToJSON *) ccnxPortalAnchor_ToJSON,
+ .display = (PARCObjectDisplay *) ccnxPortalAnchor_Display,
+ .destructor = (PARCObjectDestructor *) _ccnxPortalAnchor_Destructor
+ );
+
+void
+ccnxPortalAnchor_AssertValid(const CCNxPortalAnchor *instance)
+{
+ assertTrue(ccnxPortalAnchor_IsValid(instance),
+ "CCNxPortalAnchor is not valid.");
+}
+
+
+CCNxPortalAnchor *
+ccnxPortalAnchor_Create(const CCNxName *name, time_t expireTime)
+{
+ CCNxPortalAnchor *result = parcObject_CreateInstance(CCNxPortalAnchor);
+
+ if (result != NULL) {
+ result->prefix = ccnxName_Acquire(name);
+ result->expireTime = expireTime;
+ }
+
+ return result;
+}
+
+CCNxPortalAnchor *
+ccnxPortalAnchor_CreateFromJSON(const PARCJSON *json)
+{
+ CCNxPortalAnchor *result = parcObject_CreateInstance(CCNxPortalAnchor);
+
+ if (result != NULL) {
+ result->prefix = ccnxName_CreateFromCString(parcBuffer_Overlay(parcJSONValue_GetString(parcJSON_GetByPath(json, "/namePrefix")), 0));
+ result->expireTime = parcJSONValue_GetInteger(parcJSON_GetByPath(json, "/expireTime"));
+
+ ccnxPortalAnchor_OptionalAssertValid(result);
+ }
+
+ return result;
+}
+
+int
+ccnxPortalAnchor_Compare(const CCNxPortalAnchor *instance, const CCNxPortalAnchor *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+CCNxPortalAnchor *
+ccnxPortalAnchor_Copy(const CCNxPortalAnchor *original)
+{
+ CCNxName *prefixCopy = ccnxName_Copy(original->prefix);
+ CCNxPortalAnchor *result = ccnxPortalAnchor_Create(prefixCopy, original->expireTime);
+ ccnxName_Release(&prefixCopy);
+
+ return result;
+}
+
+void
+ccnxPortalAnchor_Display(const CCNxPortalAnchor *anchor, int indentation)
+{
+ char *prefix = ccnxName_ToString(anchor->prefix);
+
+ parcDisplayIndented_PrintLine(indentation, "CCNxPortalAnchor@%p {", anchor);
+ parcDisplayIndented_PrintLine(indentation + 1, ".prefix=%s}", prefix);
+ parcDisplayIndented_PrintLine(indentation + 1, ".expireTime=%ld", anchor->expireTime);
+
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+ parcMemory_Deallocate(&prefix);
+}
+
+bool
+ccnxPortalAnchor_Equals(const CCNxPortalAnchor *x, const CCNxPortalAnchor *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (ccnxName_Equals(x->prefix, y->prefix)) {
+ if (x->expireTime == y->expireTime) {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+ccnxPortalAnchor_HashCode(const CCNxPortalAnchor *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+ccnxPortalAnchor_IsValid(const CCNxPortalAnchor *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+ccnxPortalAnchor_ToJSON(const CCNxPortalAnchor *anchor)
+{
+ ccnxPortalAnchor_OptionalAssertValid(anchor);
+
+ PARCJSON *result = parcJSON_Create();
+ if (result != NULL) {
+ char *prefix = ccnxName_ToString(anchor->prefix);
+
+ parcJSON_AddString(result, "namePrefix", prefix);
+ parcJSON_AddInteger(result, "expireTime", (int64_t) anchor->expireTime);
+
+ parcMemory_Deallocate(&prefix);
+ }
+
+ return result;
+}
+
+PARCBufferComposer *
+ccnxPortalAnchor_BuildString(const CCNxPortalAnchor *anchor, PARCBufferComposer *composer)
+{
+ char *name = ccnxName_ToString(anchor->prefix);
+
+ char expireTime[64];
+ if (anchor->expireTime == -1) {
+ strcpy(expireTime, " never");
+ } else {
+ parcTime_TimeAsRFC3339(anchor->expireTime, expireTime);
+ }
+ parcBufferComposer_Format(composer, "{ %s %s }", name, expireTime);
+
+ parcMemory_Deallocate(&name);
+
+ return composer;
+}
+
+char *
+ccnxPortalAnchor_ToString(const CCNxPortalAnchor *anchor)
+{
+ ccnxPortalAnchor_OptionalAssertValid(anchor);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ ccnxPortalAnchor_BuildString(anchor, composer);
+ char *result = parcBufferComposer_ToString(composer);
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+CCNxPortalAnchor *
+ccnxPortalAnchor_Deserialize(PARCBuffer *buffer)
+{
+ PARCJSON *json = parcJSON_ParseBuffer(buffer);
+
+ CCNxPortalAnchor *result = ccnxPortalAnchor_CreateFromJSON(json);
+ parcJSON_Release(&json);
+ return result;
+}
+
+PARCBufferComposer *
+ccnxPortalAnchor_Serialize(const CCNxPortalAnchor *namePrefix, PARCBufferComposer *composer)
+{
+ PARCJSON *json = ccnxPortalAnchor_ToJSON(namePrefix);
+
+ char *string = parcJSON_ToString(json);
+ parcBufferComposer_PutString(composer, string);
+ parcMemory_Deallocate(&string);
+ parcJSON_Release(&json);
+ return composer;
+}
+
+CCNxName *
+ccnxPortalAnchor_GetNamePrefix(const CCNxPortalAnchor *anchor)
+{
+ return anchor->prefix;
+}
+
+time_t
+ccnxPortalAnchor_GetExpireTime(const CCNxPortalAnchor *anchor)
+{
+ return anchor->expireTime;
+}
+
+time_t
+ccnxPortalAnchor_SetExpireTime(CCNxPortalAnchor *anchor, const time_t expireTime)
+{
+ time_t previousExpireTime = anchor->expireTime;
+ anchor->expireTime = expireTime;
+ return previousExpireTime;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.h
new file mode 100644
index 00000000..fbf576f2
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAnchor.h
@@ -0,0 +1,396 @@
+/*
+ * 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_PortalAnchor.h
+ * @brief CCN Routing control for CCNxPortal
+ *
+ */
+#ifndef CCNxPortal_ccnx_PortalAnchor
+#define CCNxPortal_ccnx_PortalAnchor
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+#include <ccnx/common/ccnx_Name.h>
+
+struct CCNxPortalAnchor;
+typedef struct CCNxPortalAnchor CCNxPortalAnchor;
+
+/**
+ * Increase the number of references to a `CCNxPortalAnchor` instance.
+ *
+ * Note that new `CCNxPortalAnchor` is not created,
+ * only that the given `CCNxPortalAnchor` reference count is incremented.
+ * Discard the reference by invoking `ccnxPortalAnchor_Release`.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create();
+ *
+ * CCNxPortalAnchor *b = ccnxPortalAnchor_Acquire();
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * ccnxPortalAnchor_Release(&b);
+ * }
+ * @endcode
+ */
+CCNxPortalAnchor *ccnxPortalAnchor_Acquire(const CCNxPortalAnchor *instance);
+
+#ifdef CCNxPortal_DISABLE_VALIDATION
+# define ccnxPortalAnchor_OptionalAssertValid(_instance_)
+#else
+# define ccnxPortalAnchor_OptionalAssertValid(_instance_) ccnxPortalAnchor_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `CCNxPortalAnchor` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * ccnxPortalAnchor_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * ccnxPortalAnchor_Release(&b);
+ * }
+ * @endcode
+ */
+void ccnxPortalAnchor_AssertValid(const CCNxPortalAnchor *instance);
+
+/**
+ * Create an instance of CCNxPortalAnchor
+ *
+ * @return non-NULL A pointer to a valid CCNxPortalAnchor instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * }
+ * @endcode
+ */
+CCNxPortalAnchor *ccnxPortalAnchor_Create(const CCNxName *name, time_t expireTime);
+
+/**
+ * Create an instance of `CCNxPortalAnchor` from an instance of `PARCJSON`.
+ *
+ * @return non-NULL A pointer to a valid CCNxPortalAnchor instance.
+ * @return NULL An error occurred.
+ */
+CCNxPortalAnchor *ccnxPortalAnchor_CreateFromJSON(const PARCJSON *json);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ * @param [in] other A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ * CCNxPortalAnchor *b = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * if (ccnxPortalAnchor_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * ccnxPortalAnchor_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see ccnxPortalAnchor_Equals
+ */
+int ccnxPortalAnchor_Compare(const CCNxPortalAnchor *instance, const CCNxPortalAnchor *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `CCNxPortalAnchor` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * CCNxPortalAnchor *copy = ccnxPortalAnchor_Copy(&b);
+ *
+ * ccnxPortalAnchor_Release(&b);
+ * ccnxPortalAnchor_Release(&copy);
+ * }
+ * @endcode
+ */
+CCNxPortalAnchor *ccnxPortalAnchor_Copy(const CCNxPortalAnchor *original);
+
+/**
+ * Print a human readable representation of the given `CCNxPortalAnchor`.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * ccnxPortalAnchor_Display(a, 0);
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * }
+ * @endcode
+ */
+void ccnxPortalAnchor_Display(const CCNxPortalAnchor *instance, int indentation);
+
+/**
+ * Determine if two `CCNxPortalAnchor` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxPortalAnchor` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `ccnxPortalAnchor_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxPortalAnchor_Equals(x, y)` must return true if and only if
+ * `ccnxPortalAnchor_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxPortalAnchor_Equals(x, y)` returns true and
+ * `ccnxPortalAnchor_Equals(y, z)` returns true,
+ * then `ccnxPortalAnchor_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxPortalAnchor_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxPortalAnchor_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid CCNxPortalAnchor instance.
+ * @param [in] y A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ * CCNxPortalAnchor *b = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * if (ccnxPortalAnchor_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * ccnxPortalAnchor_Release(&b);
+ * }
+ * @endcode
+ * @see ccnxPortalAnchor_HashCode
+ */
+bool ccnxPortalAnchor_Equals(const CCNxPortalAnchor *x, const CCNxPortalAnchor *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the 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 {@link ccnxPortalAnchor_Equals} method,
+ * then calling the {@link ccnxPortalAnchor_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link ccnxPortalAnchor_Equals} function,
+ * then calling the `ccnxPortalAnchor_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * PARCHashCode hashValue = ccnxPortalAnchor_HashCode(buffer);
+ * ccnxPortalAnchor_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode ccnxPortalAnchor_HashCode(const CCNxPortalAnchor *instance);
+
+/**
+ * Determine if an instance of `CCNxPortalAnchor` 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] instance A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * if (ccnxPortalAnchor_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool ccnxPortalAnchor_IsValid(const CCNxPortalAnchor *instance);
+
+/**
+ * Release a previously acquired reference to the given `CCNxPortalAnchor` 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] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * }
+ * @endcode
+ */
+void ccnxPortalAnchor_Release(CCNxPortalAnchor **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * PARCJSON *json = ccnxPortalAnchor_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * ccnxPortalAnchor_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *ccnxPortalAnchor_ToJSON(const CCNxPortalAnchor *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `CCNxPortalAnchor`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid CCNxPortalAnchor instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalAnchor *a = ccnxPortalAnchor_Create(name, expireTime);
+ *
+ * char *string = ccnxPortalAnchor_ToString(a);
+ *
+ * ccnxPortalAnchor_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see ccnxPortalAnchor_Display
+ */
+char *ccnxPortalAnchor_ToString(const CCNxPortalAnchor *instance);
+
+/**
+ * Append a representation of the specified `CCNxPortalAnchor` instance to the given `PARCBufferComposer`.
+ *
+ * @param [in] name A pointer to a `CCNxPortalAnchor` 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(name, expireTime);
+ *
+ * ccnxPortalAnchor_BuildString(anchor, result);
+ *
+ * char *string = parcBufferComposer_ToString(result);
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate(string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *ccnxPortalAnchor_BuildString(const CCNxPortalAnchor *anchor, PARCBufferComposer *composer);
+
+CCNxPortalAnchor *ccnxPortalAnchor_Deserialize(PARCBuffer *buffer);
+
+PARCBufferComposer *ccnxPortalAnchor_Serialize(const CCNxPortalAnchor *anchor, PARCBufferComposer *composer);
+
+CCNxName *ccnxPortalAnchor_GetNamePrefix(const CCNxPortalAnchor *anchor);
+
+time_t ccnxPortalAnchor_GetExpireTime(const CCNxPortalAnchor *anchor);
+
+time_t ccnxPortalAnchor_SetExpireTime(CCNxPortalAnchor *anchor, const time_t expireTime);
+#endif
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.c
new file mode 100644
index 00000000..0b154bea
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.c
@@ -0,0 +1,39 @@
+/*
+ * 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/api/ccnx_Portal/ccnx_PortalAttributes.h>
+
+struct ccnx_portal_attributes {
+ bool logging;
+};
+
+/**
+ * Non-blocking (reads)
+ */
+const CCNxPortalAttributes ccnxPortalAttributes_NonBlocking = {
+ .logging = false
+};
+
+bool
+ccnxPortalAttributes_IsLogging(const CCNxPortalAttributes *attributes)
+{
+ return attributes->logging;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.h
new file mode 100755
index 00000000..1e789b62
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalAttributes.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 ccnx_PortalAttributes.h
+ * @brief Attributes related to the `CCNxPortal` instance.
+ *
+ */
+#ifndef __CCNx_Portal_API__ccnx_PortalAttributes__
+#define __CCNx_Portal_API__ccnx_PortalAttributes__
+
+#include <stdbool.h>
+
+struct ccnx_portal_attributes;
+/**
+ * @brief The attributes for the instance of {@link CCNxPortal}
+ */
+typedef struct ccnx_portal_attributes CCNxPortalAttributes;
+
+/**
+ * Non-blocking (reads)
+ */
+extern const CCNxPortalAttributes ccnxPortalAttributes_NonBlocking;
+
+/**
+ * Return `true` if the given attributes indicate Portal Logging is enabled.
+ *
+ * @param [in] attributes A pointer to a valid {@link CCNxPortalAttributes} instance.
+ *
+ * @return `true` If the given attributes indicate Portal Logging is enabled.
+ * @return `false` If the given attributes do not indicate Portal Logging is enabled.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxPortalAttributes_IsLogging(const CCNxPortalAttributes *attributes);
+
+#endif /* defined(__CCNx_Portal_API__ccnx_PortalAttributes__) */
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.c
new file mode 100755
index 00000000..be5810bd
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.c
@@ -0,0 +1,136 @@
+/*
+ * 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 <sys/errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalFactory.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_Security.h>
+
+const char *CCNxPortalFactory_LocalRouterName = "/localstack/portalFactory/LocalRouterName";
+const char *CCNxPortalFactory_LocalForwarder = "/localstack/portalFactory/LocalForwarder";
+const char *CCNxPortalFactory_LocalRouterTimeout = "/localstack/portalFactory/LocalRouterTimeout";
+
+struct CCNxPortalFactory {
+ const PARCIdentity *identity;
+ const PARCSigner *signer;
+ const PARCKeyId *keyId;
+ const CCNxPortalAttributes *attributeTemplate;
+ PARCProperties *properties;
+};
+
+static void
+_ccnxPortalFactory_Destroy(CCNxPortalFactory **factoryPtr)
+{
+ CCNxPortalFactory *factory = *factoryPtr;
+
+ parcIdentity_Release((PARCIdentity **) &factory->identity);
+
+ parcSigner_Release((PARCSigner **) &factory->signer);
+
+ parcKeyId_Release((PARCKeyId **) &factory->keyId);
+
+ parcProperties_Release(&factory->properties);
+
+ parcSecurity_Fini();
+}
+
+parcObject_ExtendPARCObject(CCNxPortalFactory, _ccnxPortalFactory_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(ccnxPortalFactory, CCNxPortalFactory);
+
+parcObject_ImplementRelease(ccnxPortalFactory, CCNxPortalFactory);
+
+CCNxPortalFactory *
+ccnxPortalFactory_Create(const PARCIdentity *identity)
+{
+ parcIdentity_OptionalAssertValid(identity);
+
+ parcSecurity_Init();
+ CCNxPortalFactory *result = parcObject_CreateInstance(CCNxPortalFactory);
+ if (result != NULL) {
+ result->identity = parcIdentity_Acquire(identity);
+ result->signer = parcIdentity_CreateSigner(identity);
+ result->keyId = parcSigner_CreateKeyId(result->signer);
+ result->properties = parcProperties_Create();
+
+ ccnxPortalFactory_SetProperty(result, CCNxPortalFactory_LocalRouterName, "lci:/local/dcr");
+ ccnxPortalFactory_SetProperty(result, CCNxPortalFactory_LocalForwarder, "tcp://127.0.0.1:9695");
+ ccnxPortalFactory_SetProperty(result, CCNxPortalFactory_LocalRouterTimeout, "1000000");
+ }
+ return result;
+}
+
+const PARCIdentity *
+ccnxPortalFactory_GetIdentity(const CCNxPortalFactory *factory)
+{
+ return factory->identity;
+}
+
+const PARCKeyId *
+ccnxPortalFactory_GetKeyId(const CCNxPortalFactory *factory)
+{
+ return factory->keyId;
+}
+
+void
+ccnxPortalFactory_Display(const CCNxPortalFactory *factory, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "CCNxPortalFactory@%p {", factory);
+
+ parcIdentity_Display(factory->identity, indentation + 1);
+ parcProperties_Display(factory->properties, indentation + 1);
+
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+CCNxPortal *
+ccnxPortalFactory_CreatePortal(const CCNxPortalFactory *factory, CCNxStackImpl *stackImplementation)
+{
+ return stackImplementation(factory, &ccnxPortalAttributes_NonBlocking);
+}
+
+PARCProperties *
+ccnxPortalFactory_GetProperties(const CCNxPortalFactory *factory)
+{
+ return factory->properties;
+}
+
+const char *
+ccnxPortalFactory_GetProperty(const CCNxPortalFactory *factory, const char *restrict name, const char *restrict defaultValue)
+{
+ return parcProperties_GetPropertyDefault(factory->properties, name, defaultValue);
+}
+
+void
+ccnxPortalFactory_SetProperty(const CCNxPortalFactory *factory, const char *restrict name, const char *restrict value)
+{
+ parcProperties_SetProperty(factory->properties, name, value);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.h
new file mode 100755
index 00000000..e021b92d
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalFactory.h
@@ -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.
+ */
+
+/**
+ * @file ccnx_PortalFactory.h
+ * @brief An API for creating Portals.
+ *
+ */
+#ifndef CCNx_Portal_API_ccnx_PortalFactory_h
+#define CCNx_Portal_API_ccnx_PortalFactory_h
+
+struct CCNxPortalFactory;
+/**
+ * @typedef CCNxPortalFactory
+ * @brief A Portal factory.
+ */
+typedef struct CCNxPortalFactory CCNxPortalFactory;
+
+#include <parc/algol/parc_Properties.h>
+#include <parc/security/parc_Identity.h>
+#include <parc/security/parc_KeyId.h>
+
+#include <ccnx/transport/common/transport.h>
+#include <ccnx/transport/common/transport_MetaMessage.h>
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+
+extern const char *CCNxPortalFactory_LocalRouterName;
+extern const char *CCNxPortalFactory_LocalForwarder;
+extern const char *CCNxPortalFactory_LocalRouterTimeout;
+
+/**
+ * Create a `CCNxPortalFactory` with the given {@link PARCIdentity}.
+ *
+ * If successful, a new reference to the given `PARCIdentity`
+ * instance is acquired and released when the result is eventually released
+ * via {@link ccnxPortalFactory_Release}.
+ * The caller must release its original reference.
+ *
+ * The given `PARCIdentity` is the identity used for interacting with the Transport Framework when creating a new stack.
+ * The default behaviour is that identity is also used for subsequent Content Object signing operations.
+ * It is permissable, however, to set a different identity,
+ * after a Portal API instance is created should its associated Transport Stack support setting a new identity.
+ *
+ * @param [in] identity A pointer to a `PARCIdentity` instance.
+ *
+ * @return non-NULL A pointer to a `CCNxPortalFactory` instance.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * char *subjectName = "An Example";
+ * char *keystoreName = "keystore";
+ * char *keystorePassword = "password";
+ *
+ * bool success = parcPkcs12KeyStore_CreateFile(keystoreName, keystorePassword, subjectName, 1024, 30);
+ *
+ * PARCIdentity *identity =
+ * parcIdentity_Create(parcIdentityFile_Create(keystoreName, keystorePassword), PARCIdentityFileAsPARCIdentity);
+ *
+ * CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+ * parcIdentity_Release(&identity);
+ *
+ * ccnxPortalFactory_Release(&factory);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortalFactory_Acquire}
+ * @see {@link ccnxPortalFactory_Release}
+ */
+CCNxPortalFactory *ccnxPortalFactory_Create(const PARCIdentity *identity);
+
+/**
+ * Print a human readable representation of the given `CCNxPortalFactory` instance.
+ *
+ * @param [in] factory A pointer to the instance of `CCNxPortalFactory` to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalFactory *factory = ccnxPortalFactory_Create(...);
+ *
+ * ccnxPortalFactory_Display(0, factory);
+ *
+ * ccnxPortalFactory_Release(&factory);
+ * }
+ * @endcode
+ *
+ */
+void ccnxPortalFactory_Display(const CCNxPortalFactory *factory, int indentation);
+
+/**
+ * Increase the number of references to a `CCNxPortalFactory` instance.
+ *
+ * Note that new `CCNxPortalFactory` is not created,
+ * only that the given `CCNxPortalFactory` reference count is incremented.
+ * Discard the reference by invoking `ccnxPortalFactory_Release`.
+ *
+ * @param [in] instance A pointer to a valid `CCNxPortalFactory`.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalFactory *x = ccnxPortalFactory_Create(...);
+ *
+ * CCNxPortalFactory *x2 = ccnxPortalFactory_Acquire(x);
+ *
+ * ccnxPortalFactory_Release(&x);
+ * ccnxPortalFactory_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortalFactory_Release}
+ */
+CCNxPortalFactory *ccnxPortalFactory_Acquire(const CCNxPortalFactory *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] factoryPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalFactory *factory = ccnxPortalFactory_Create(...);
+ *
+ * ccnxPortalFactory_Release(&factory);
+ * }
+ * @endcode
+ */
+void ccnxPortalFactory_Release(CCNxPortalFactory **factoryPtr);
+
+/**
+ * Get the {@link PARCIdentity} associated with the given `CCNxPortalFactory`.
+ *
+ * Note: a handle to the instance is not acquired, so you must not release it.
+ *
+ * @param [in] factory A pointer to a valid `CCNxPortalFactory`.
+ *
+ * @return A pointer to the internal `PARCIdentity` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalFactory *factory = ccnxPortalFactory_Create(...);
+ *
+ * PARCIdentity *identity = ccnxPortalFactory_GetIdentity(factory);
+ *
+ * ccnxPortalFactory_Release(&factory);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortalFactory_Create}
+ */
+const PARCIdentity *ccnxPortalFactory_GetIdentity(const CCNxPortalFactory *factory);
+
+/**
+ * Get the `{@link PARCKeyId} of the {@link PARCIdentity} bound to the given CCNxPortalFactory.
+ *
+ * @param [in] factory A pointer to a valid `CCNxPortalFactory`.
+ *
+ * @return A pointer to the internal `PARCKeyId` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalFactory *factory = ccnxPortalFactory_Create(...);
+ *
+ * PARCKeyId *keyId = ccnxPortalFactory_GetKeyId(factory);
+ *
+ * ccnxPortalFactory_Release(&factory);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortalFactory_Create}
+ */
+const PARCKeyId *ccnxPortalFactory_GetKeyId(const CCNxPortalFactory *factory);
+
+/**
+ * @typedef CCNxStackImpl
+ * @brief A function that creates a `CCNxPortal` given a factory and attributes.
+ */
+typedef CCNxPortal *(CCNxStackImpl)(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes);
+
+/**
+ * Create an {@link CCNxPortal} instance of the specified communication type, protocol and attributes.
+ *
+ * @param [in] factory A pointer to a CCNxPortal factory to use to create the instance.
+ * @param [in,out] stackImplementation A pointer to a function initializing the protocol implementation.
+ *
+ * @return NULL An error occurred in creating the instance. See the value of `errno`
+ * @return non-NULL A pointer to a valid `CCNxPortal` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Message);
+ *
+ * ccnxPortal_Release(&portal);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortal_Release}
+ */
+CCNxPortal *ccnxPortalFactory_CreatePortal(const CCNxPortalFactory *factory, CCNxStackImpl *stackImplementation);
+
+PARCProperties *ccnxPortalFactory_GetProperties(const CCNxPortalFactory *factory);
+
+const char *ccnxPortalFactory_GetProperty(const CCNxPortalFactory *factory, const char *restrict name, const char *restrict defaultValue);
+
+void ccnxPortalFactory_SetProperty(const CCNxPortalFactory *factory, const char *restrict name, const char *restrict value);
+
+#endif // CCNx_Portal_API_ccnx_Portal_h
+
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.c
new file mode 100755
index 00000000..f032e2c8
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.c
@@ -0,0 +1,452 @@
+/*
+ * 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 <sys/errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <poll.h>
+#include <stdio.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalRTA.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalFactory.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalStack.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+#include <parc/security/parc_Signer.h>
+
+#include <ccnx/api/control/cpi_Forwarding.h>
+#include <ccnx/api/control/cpi_ControlMessage.h>
+#include <ccnx/api/control/cpi_ControlFacade.h>
+#include <ccnx/transport/common/transport_MetaMessage.h>
+#include <ccnx/transport/common/ccnx_StackConfig.h>
+#include <ccnx/transport/common/ccnx_ConnectionConfig.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+#include <ccnx/api/notify/notify_Status.h>
+
+#include <ccnx/transport/transport_rta/rta_Transport.h>
+
+#include <ccnx/transport/transport_rta/config/config_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/config/config_ApiConnector.h>
+#include <ccnx/transport/transport_rta/config/config_FlowControl_Vegas.h>
+#include <ccnx/transport/transport_rta/config/config_Codec_Tlv.h>
+#include <ccnx/transport/transport_rta/config/config_Forwarder_Local.h>
+#include <ccnx/transport/transport_rta/config/config_Forwarder_Metis.h>
+#include <ccnx/transport/transport_rta/config/config_PublicKeySigner.h>
+
+static const uint16_t ccnxPortal_MetisPort = 9695;
+
+typedef enum {
+ ccnxPortalTypeChunked,
+ ccnxPortalTypeMessage
+} _CCNxPortalType;
+
+typedef enum {
+ CCNxPortalProtocol_RTALoopback,
+ ccnxPortalProtocol_RTA,
+ CCNxPortalProtocol_APILoopback
+} _CCNxPortalProtocol;
+
+typedef struct _CCNxPortalRTAContext {
+ RTATransport *rtaTransport;
+ const CCNxTransportConfig *(*createTransportConfig)(const CCNxPortalFactory *, _CCNxPortalType, _CCNxPortalProtocol);
+ const CCNxTransportConfig *configuration;
+ int fileId;
+ PARCLog *logger;
+} _CCNxPortalRTAContext;
+
+static void
+_ccnxPortalRTAContext_Destroy(_CCNxPortalRTAContext **instancePtr)
+{
+ _CCNxPortalRTAContext *instance = *instancePtr;
+
+ rtaTransport_Close(instance->rtaTransport, instance->fileId);
+ rtaTransport_Destroy(&instance->rtaTransport);
+
+ ccnxTransportConfig_Destroy((CCNxTransportConfig **) &instance->configuration);
+ parcLog_Release(&instance->logger);
+}
+
+parcObject_ExtendPARCObject(_CCNxPortalRTAContext, _ccnxPortalRTAContext_Destroy,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+static parcObject_ImplementRelease(_ccnxPortalRTAContext, _CCNxPortalRTAContext);
+
+static _CCNxPortalRTAContext *
+_ccnxPortalRTAContext_Create(RTATransport *rtaTransport, const CCNxTransportConfig *configuration, int fileId)
+{
+ _CCNxPortalRTAContext *result = parcObject_CreateInstance(_CCNxPortalRTAContext);
+ if (result != NULL) {
+ result->rtaTransport = rtaTransport;
+ result->configuration = configuration;
+ result->fileId = fileId;
+
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ result->logger = parcLog_Create(NULL, "ccnxPortalRTA", NULL, reporter);
+ parcLogReporter_Release(&reporter);
+ parcLog_SetLevel(result->logger, PARCLogLevel_Debug);
+ }
+
+ return result;
+}
+
+static void
+_ccnxPortalProtocol_RTALoopback(CCNxConnectionConfig *connConfig, CCNxStackConfig *stackConfig, PARCArrayList *listOfComponentNames)
+{
+ char *bentPipeNameEnv = getenv("BENT_PIPE_NAME");
+ if (bentPipeNameEnv != NULL) {
+ } else {
+ printf("The BENT_PIPE_NAME environment variable needs to the name of a 'fifo' file. Try /tmp/test_ccnx_Portal\n");
+ }
+
+ parcArrayList_Add(listOfComponentNames, (char *) tlvCodec_GetName());
+ tlvCodec_ProtocolStackConfig(stackConfig);
+ tlvCodec_ConnectionConfig(connConfig);
+
+ parcArrayList_Add(listOfComponentNames, (char *) localForwarder_GetName());
+ localForwarder_ProtocolStackConfig(stackConfig);
+ localForwarder_ConnectionConfig(connConfig, bentPipeNameEnv);
+}
+
+static void
+_ccnxPortalProtocol_RTAMetis(CCNxConnectionConfig *connConfig, CCNxStackConfig *stackConfig, PARCArrayList *listOfComponentNames)
+{
+ uint16_t metisPort = ccnxPortal_MetisPort;
+ char *metisPortEnv = getenv("METIS_PORT");
+ if (metisPortEnv != NULL) {
+ metisPort = (uint16_t) atoi(metisPortEnv);
+ }
+ parcArrayList_Add(listOfComponentNames, (char *) tlvCodec_GetName());
+ tlvCodec_ProtocolStackConfig(stackConfig);
+ tlvCodec_ConnectionConfig(connConfig);
+
+ parcArrayList_Add(listOfComponentNames, (char *) metisForwarder_GetName());
+ metisForwarder_ProtocolStackConfig(stackConfig);
+ metisForwarder_ConnectionConfig(connConfig, metisPort);
+}
+
+/**
+ * This composes a CCNxTransportConfig instance that describes a complete transport stack assembly.
+ */
+static const CCNxTransportConfig *
+_createTransportConfig(const CCNxPortalFactory *factory, _CCNxPortalType type, _CCNxPortalProtocol protocol)
+{
+ if (type == ccnxPortalTypeChunked) {
+ // Good.
+ } else if (type == ccnxPortalTypeMessage) {
+ // Good.
+ } else {
+ return NULL;
+ }
+
+ // TODO: This is in need of some narrative of what's going on here.
+
+ CCNxConnectionConfig *connConfig = ccnxConnectionConfig_Create();
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+
+ PARCArrayList *listOfComponentNames = parcArrayList_Create_Capacity(NULL, NULL, 8);
+
+ parcArrayList_Add(listOfComponentNames, (char *) apiConnector_GetName());
+
+ apiConnector_ProtocolStackConfig(stackConfig);
+ apiConnector_ConnectionConfig(connConfig);
+
+ if (type == ccnxPortalTypeChunked) {
+ parcArrayList_Add(listOfComponentNames, (char *) vegasFlowController_GetName());
+ vegasFlowController_ProtocolStackConfig(stackConfig);
+ vegasFlowController_ConnectionConfig(connConfig);
+ }
+
+ switch (protocol) {
+ case CCNxPortalProtocol_RTALoopback:
+ _ccnxPortalProtocol_RTALoopback(connConfig, stackConfig, listOfComponentNames);
+ break;
+
+ case ccnxPortalProtocol_RTA:
+ _ccnxPortalProtocol_RTAMetis(connConfig, stackConfig, listOfComponentNames);
+ break;
+
+ default:
+ errno = EPROTOTYPE;
+ assertTrue(0, "Unknown protocol type: %d", protocol);
+ }
+
+
+ protocolStack_ComponentsConfigArrayList(stackConfig, listOfComponentNames);
+ parcArrayList_Destroy(&listOfComponentNames);
+
+ const PARCIdentity *identity = ccnxPortalFactory_GetIdentity(factory);
+
+ configPublicKeySigner_SetIdentity(connConfig, identity);
+
+ CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig);
+
+ ccnxStackConfig_Release(&stackConfig);
+
+ return result;
+}
+
+static void
+_ccnxPortalRTA_Start(void *privateData)
+{
+}
+
+static void
+_ccnxPortalRTA_Stop(void *privateData)
+{
+}
+
+static bool
+_ccnxPortalRTA_Send(void *privateData, const CCNxMetaMessage *portalMessage, const CCNxStackTimeout *microSeconds)
+{
+ const _CCNxPortalRTAContext *transportContext = (_CCNxPortalRTAContext *) privateData;
+
+ bool result = rtaTransport_Send(transportContext->rtaTransport, transportContext->fileId, portalMessage, microSeconds);
+
+ return result;
+}
+
+static CCNxMetaMessage *
+_ccnxPortalRTA_Receive(void *privateData, const CCNxStackTimeout *microSeconds)
+{
+ const _CCNxPortalRTAContext *transportContext = (_CCNxPortalRTAContext *) privateData;
+
+ CCNxMetaMessage *result = NULL;
+
+ TransportIOStatus status = rtaTransport_Recv(transportContext->rtaTransport, transportContext->fileId, &result, microSeconds);
+
+ if (status != TransportIOStatus_Success) {
+ return NULL;
+ }
+
+ return result;
+}
+
+static int
+_ccnxPortalRTA_GetFileId(void *privateData)
+{
+ const _CCNxPortalRTAContext *transportContext = (_CCNxPortalRTAContext *) privateData;
+
+ return transportContext->fileId;
+}
+
+static CCNxPortalAttributes *
+_ccnxPortalRTA_GetAttributes(void *privateData)
+{
+ return NULL;
+}
+
+static bool
+_nonBlockingPortal(const _CCNxPortalRTAContext *transportContext)
+{
+ int fd = transportContext->fileId;
+ int flags;
+
+ if ((flags = fcntl(fd, F_GETFL, NULL)) != -1) {
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool
+_ccnxPortalRTA_SetAttributes(void *privateData, const CCNxPortalAttributes *attributes)
+{
+ const _CCNxPortalRTAContext *transportContext = (_CCNxPortalRTAContext *) privateData;
+
+ bool result = _nonBlockingPortal(transportContext);
+
+ return result;
+}
+
+static bool
+_ccnxPortalRTA_Listen(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ CCNxControl *control = ccnxControl_CreateAddRouteToSelfRequest(name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromControl(control);
+
+ ccnxControl_Release(&control);
+
+ bool result = _ccnxPortalRTA_Send(privateData, message, CCNxStackTimeout_Never);
+
+ // There is a problem here if the client invokes this function on a portal that is already receiving messages.
+ // This simply absorbs messages until the receipt of the acknowledgement of this listen.
+ // Perhaps what should happen is not read any messages and let the client sort it out in its read loop.
+ if (result == true) {
+ CCNxMetaMessage *response = _ccnxPortalRTA_Receive(privateData, microSeconds);
+
+ if (response != NULL) {
+ if (ccnxMetaMessage_IsControl(response)) {
+ // TODO: Check that the response was success.
+ result = true;
+ }
+ ccnxMetaMessage_Release(&response);
+ } else {
+ // We got a NULL reponse (possibly due to timeout). Since we always expect a
+ // response from the forwarder, consider this a failure.
+ result = false;
+ }
+ }
+
+ ccnxMetaMessage_Release(&message);
+
+ return result;
+}
+
+static bool
+_ccnxPortalRTA_Ignore(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ CCNxControl *control = ccnxControl_CreateRemoveRouteToSelfRequest(name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromControl(control);
+ ccnxControl_Release(&control);
+
+ bool result = _ccnxPortalRTA_Send(privateData, message, CCNxStackTimeout_Never);
+
+ // There is a problem here if the client invokes this function on a portal that is already receiving messages.
+ // This simply absorbs messages until the receipt of the acknowledgement of this listen.
+ // Perhaps what should happen is not read any messages and let the client sort it out in its read loop.
+ if (result == true) {
+ CCNxMetaMessage *response = _ccnxPortalRTA_Receive(privateData, microSeconds);
+
+ if (response != NULL) {
+ if (ccnxMetaMessage_IsControl(response)) {
+ // TODO: Check that the response was success.
+ result = true;
+ }
+ ccnxMetaMessage_Release(&response);
+ } else {
+ // We got a NULL reponse (possibly due to timeout). Since we always expect a
+ // response from the forwarder, consider this a failure.
+ result = false;
+ }
+ }
+
+ ccnxMetaMessage_Release(&message);
+
+ return result;
+}
+
+static bool
+_ccnxPortalRTA_IsConnected(CCNxPortal *portal)
+{
+ bool result = false;
+
+ CCNxMetaMessage *response;
+
+ if ((response = ccnxPortal_Receive(portal, CCNxStackTimeout_Never)) != NULL) {
+ if (ccnxMetaMessage_IsControl(response)) {
+ CCNxControl *control = ccnxMetaMessage_GetControl(response);
+
+ if (ccnxControl_IsNotification(control)) {
+ NotifyStatus *status = ccnxControl_GetNotifyStatus(control);
+
+ if (notifyStatus_IsConnectionOpen(status) == true) {
+ result = true;
+ }
+ notifyStatus_Release(&status);
+ }
+ }
+ ccnxMetaMessage_Release(&response);
+ }
+
+ return result;
+}
+
+static CCNxPortal *
+_ccnxPortalRTA_CreatePortal(const CCNxPortalFactory *factory,
+ _CCNxPortalType type,
+ _CCNxPortalProtocol protocol,
+ const CCNxPortalAttributes *attributes)
+{
+ CCNxPortal *result = NULL;
+
+ const CCNxTransportConfig *configuration = _createTransportConfig(factory, type, protocol);
+
+ if (ccnxTransportConfig_IsValid(configuration) == false) {
+ return NULL;
+ }
+
+ RTATransport *rtaTransport = rtaTransport_Create();
+ if (rtaTransport != NULL) {
+ int fileDescriptor = rtaTransport_Open(rtaTransport, (CCNxTransportConfig *) configuration);
+
+ _CCNxPortalRTAContext *transportContext = _ccnxPortalRTAContext_Create(rtaTransport, configuration, fileDescriptor);
+
+ if (transportContext != NULL) {
+ CCNxPortalStack *implementation =
+ ccnxPortalStack_Create(factory,
+ attributes,
+ _ccnxPortalRTA_Start,
+ _ccnxPortalRTA_Stop,
+ _ccnxPortalRTA_Receive,
+ _ccnxPortalRTA_Send,
+ _ccnxPortalRTA_Listen,
+ _ccnxPortalRTA_Ignore,
+ _ccnxPortalRTA_GetFileId,
+ _ccnxPortalRTA_SetAttributes,
+ _ccnxPortalRTA_GetAttributes,
+ transportContext,
+ (void (*)(void **))_ccnxPortalRTAContext_Release);
+
+ result = ccnxPortal_Create(attributes, implementation);
+
+ if (result != NULL) {
+ if (_ccnxPortalRTA_IsConnected(result) == true) {
+ _nonBlockingPortal(transportContext);
+ } else {
+ ccnxPortal_Release(&result);
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+CCNxPortal *
+ccnxPortalRTA_Message(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes)
+{
+ return _ccnxPortalRTA_CreatePortal(factory, ccnxPortalTypeMessage, ccnxPortalProtocol_RTA, attributes);
+}
+
+CCNxPortal *
+ccnxPortalRTA_Chunked(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes)
+{
+ return _ccnxPortalRTA_CreatePortal(factory, ccnxPortalTypeChunked, ccnxPortalProtocol_RTA, attributes);
+}
+
+CCNxPortal *
+ccnxPortalRTA_LoopBack(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes)
+{
+ return _ccnxPortalRTA_CreatePortal(factory, ccnxPortalTypeMessage, CCNxPortalProtocol_RTALoopback, attributes);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.h
new file mode 100755
index 00000000..157ad203
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalRTA.h
@@ -0,0 +1,82 @@
+/*
+ * 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_PortalRTA.h
+ * @brief The CCNxPortalStack representation of an "RTA" Transport Stack
+ *
+ */
+#ifndef __CCNx_Portal_API__ccnx_PortalRTA__
+#define __CCNx_Portal_API__ccnx_PortalRTA__
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAttributes.h>
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+
+/**
+ * Specification for an "RTA" Tranport Stack configured for Message-by-Message interaction.
+ *
+ * @param [in] factory A pointer to a valid {@link CCNxPortalFactory} instance.
+ * @param [in] attributes A pointer to a valid {@link CCNxPortalAttributes} instance.
+ *
+ * @return non-NULL A pointer to a valid {@link CCNxPortal} instance bound to the specified Transport Stack.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Message);
+ * }
+ * @endcode
+ */
+CCNxPortal *ccnxPortalRTA_Message(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes);
+
+/**
+ * Specification for an "RTA" Tranport Stack configured for Chunked interaction.
+ *
+ * The flow of inbound Content Objects is initiated by the first `CCNxInterest` specifying a valid Chunked protocol.
+ *
+ * @param [in] factory A pointer to a valid {@link CCNxPortalFactory} instance.
+ * @param [in] attributes A pointer to a valid {@link CCNxPortalAttributes} instance.
+ *
+ * @return non-NULL A pointer to a valid {@link CCNxPortal} instance bound to the specified Transport Stack.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Chunked);
+ * }
+ * @endcode
+ */
+CCNxPortal *ccnxPortalRTA_Chunked(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes);
+
+/**
+ * Specification for an "RTA" Tranport Stack configured for a loopback, Message-by-Message interaction.
+ *
+ * The loopback causes all messages sent to be reflected back to be received.
+ *
+ * @param [in] factory A pointer to a valid {@link CCNxPortalFactory} instance.
+ * @param [in] attributes A pointer to a valid {@link CCNxPortalAttributes} instance.
+ *
+ * @return non-NULL A pointer to a valid {@link CCNxPortal} instance bound to the specified Transport Stack.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_LoopBack);
+ * }
+ * @endcode
+ */
+CCNxPortal *ccnxPortalRTA_LoopBack(const CCNxPortalFactory *factory, const CCNxPortalAttributes *attributes);
+
+#endif /* defined(__CCNx_Portal_API__ccnx_PortalRTA__) */
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.c b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.c
new file mode 100755
index 00000000..5490c44d
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.c
@@ -0,0 +1,191 @@
+/*
+ * 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/errno.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalStack.h>
+
+#include <parc/algol/parc_Object.h>
+
+struct CCNxPortalStack {
+ CCNxPortalFactory *factory;
+
+ const CCNxPortalAttributes *attributes;
+
+ void *privateData;
+
+ void (*start)(void *privateData);
+
+ void (*stop)(void *privateData);
+
+ CCNxMetaMessage *(*read)(void *privateData, const CCNxStackTimeout *microSeconds);
+
+ bool (*write)(void *privateData, const CCNxMetaMessage *portalMessage, const CCNxStackTimeout *microSeconds);
+
+ bool (*listen)(void *privateData, const CCNxName *restrict name, const CCNxStackTimeout *microSeconds);
+
+ bool (*ignore)(void *privateData, const CCNxName *restrict name, const CCNxStackTimeout *microSeconds);
+
+ int (*getFileId)(void *privateData);
+
+ bool (*setAttributes)(void *privateData, const CCNxPortalAttributes *attributes);
+
+ CCNxPortalAttributes * (*getAttributes)(void *privateData);
+
+ void (*releasePrivateData)(void **privateData);
+};
+
+static void
+_destroy(CCNxPortalStack **instancePtr)
+{
+ CCNxPortalStack *instance = *instancePtr;
+
+ if (instance->privateData != NULL) {
+ instance->releasePrivateData(&instance->privateData);
+ }
+
+ ccnxPortalFactory_Release(&instance->factory);
+}
+
+parcObject_ExtendPARCObject(CCNxPortalStack, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(ccnxPortalStack, CCNxPortalStack);
+
+parcObject_ImplementRelease(ccnxPortalStack, CCNxPortalStack);
+
+CCNxPortalStack *
+ccnxPortalStack_Create(const CCNxPortalFactory *factory,
+ const CCNxPortalAttributes *attributes,
+ void (*start)(void *privateData),
+ void (*stop)(void *privateData),
+ CCNxMetaMessage *(*receive)(void *privateData, const CCNxStackTimeout *microSeconds),
+ bool (*send)(void *privateData, const CCNxMetaMessage *message, const CCNxStackTimeout *microSeconds),
+ bool (*listen)(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds),
+ bool (*ignore)(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds),
+ int (*getFileId)(void *privateData),
+ bool (*setAttributes)(void *privateData, const CCNxPortalAttributes *attributes),
+ CCNxPortalAttributes * (*getAttributes)(void *privateData),
+ void *privateData,
+ void (*releasePrivateData)(void **privateData))
+{
+ CCNxPortalStack *result = parcObject_CreateInstance(CCNxPortalStack);
+
+ if (result != NULL) {
+ result->factory = ccnxPortalFactory_Acquire(factory);
+ result->attributes = attributes;
+ result->start = start;
+ result->stop = stop;
+ result->read = receive;
+ result->write = send;
+ result->getFileId = getFileId;
+ result->listen = listen;
+ result->ignore = ignore;
+ result->setAttributes = setAttributes;
+ result->getAttributes = getAttributes;
+ result->privateData = privateData;
+ result->releasePrivateData = releasePrivateData;
+ }
+ return result;
+}
+
+bool
+ccnxPortalStack_Start(const CCNxPortalStack *portalStack)
+{
+ portalStack->start(portalStack->privateData);
+ return true;
+}
+
+bool
+ccnxPortalStack_Stop(const CCNxPortalStack *portalStack)
+{
+ portalStack->stop(portalStack->privateData);
+ return true;
+}
+
+CCNxMetaMessage *
+ccnxPortalStack_Receive(const CCNxPortalStack *restrict portalStack, const CCNxStackTimeout *microSeconds)
+{
+ CCNxMetaMessage *result = portalStack->read(portalStack->privateData, microSeconds);
+
+ return result;
+}
+
+bool
+ccnxPortalStack_Send(const CCNxPortalStack *portalStack, const CCNxMetaMessage *portalMessage, const CCNxStackTimeout *microSeconds)
+{
+ return portalStack->write(portalStack->privateData, portalMessage, microSeconds);
+}
+
+bool
+ccnxPortalStack_SetAttributes(const CCNxPortalStack *portalStack, const CCNxPortalAttributes *attributes)
+{
+ return portalStack->setAttributes(portalStack->privateData, attributes);
+}
+
+bool
+ccnxPortalStack_Listen(const CCNxPortalStack *portalStack, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ return portalStack->listen(portalStack->privateData, name, microSeconds);
+}
+
+bool
+ccnxPortalStack_Ignore(const CCNxPortalStack *portalStack, const CCNxName *name, const CCNxStackTimeout *microSeconds)
+{
+ return portalStack->ignore(portalStack->privateData, name, microSeconds);
+}
+
+int
+ccnxPortalStack_GetErrorCode(const CCNxPortalStack *portalStack)
+{
+#ifndef _ANDROID_
+ extern int errno;
+#endif
+ return errno;
+}
+
+const CCNxPortalAttributes *
+ccnxPortalStack_GetAttributes(const CCNxPortalStack *portalStack)
+{
+ return portalStack->attributes;
+}
+
+int
+ccnxPortalStack_GetFileId(const CCNxPortalStack *portalStack)
+{
+ return portalStack->getFileId(portalStack->privateData);
+}
+
+const PARCKeyId *
+ccnxPortalStack_GetKeyId(const CCNxPortalStack *portalStack)
+{
+ return ccnxPortalFactory_GetKeyId(portalStack->factory);
+}
+
+PARCProperties *
+ccnxPortalStack_GetProperties(const CCNxPortalStack *portalStack)
+{
+ return ccnxPortalFactory_GetProperties(portalStack->factory);
+}
+
+const char *
+ccnxPortalStack_GetProperty(const CCNxPortalStack *portalStack, const char *restrict name, const char *restrict defaultValue)
+{
+ return ccnxPortalFactory_GetProperty(portalStack->factory, name, defaultValue);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.h b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.h
new file mode 100755
index 00000000..b119213a
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/ccnx_PortalStack.h
@@ -0,0 +1,330 @@
+/*
+ * 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_PortalStack.h
+ * @brief A polymorphic interface to different Portal Stack implementations.
+ *
+ */
+#ifndef CCNx_Portal_API_ccnx_PortalImplementation_h
+#define CCNx_Portal_API_ccnx_PortalImplementation_h
+
+struct CCNxPortalStack;
+/**
+ * @typedef CCNxPortalStack
+ * @brief A set of functions and state for the Portal instance.
+ */
+typedef struct CCNxPortalStack CCNxPortalStack;
+
+#include <parc/algol/parc_Properties.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalFactory.h>
+
+/**
+ * Create function for a `CCNxPortalStack`
+ *
+ * @param [in] factory An instance of a {@link CCNxPortalFactory}.
+ * @param [in] start A pointer to a function that takes `*privateData` as a parameter.
+ * @param [in] stop A pointer to a function that takes `*privateData` as a parameter.
+ * @param [in] receiveFunction A pointer to a function that takes `*privateData` as a parameter and returns a pointer to a {@link CCNxMetaMessage}.
+ * @param [in] send A pointer to a function that takes `*privateData` and `*portalMessage` as parameters.
+ * @param [in] listen A pointer to a function that takes `*privateData` and a {@link CCNxName} as parameters.
+ * @param [in] ignore A pointer to a function that takes `*privateData` and a {@link CCNxName} as parameters.
+ * @param [in] getFileId A pointer to a function that takes `*privateData` as a parameter and returns an `int`.
+ * @param [in] setAttributes A pointer to a function that takes `*privateData` and a {@link CCNxPortalAttributes} as parameters.
+ * @param [in] getAttributes A pointer to a function that takes `*privateData` as a parameter and returns an instance of `CCNxPortalAttributes`.
+ * @param [in] privateData A pointer to some data.
+ * @param [in] releasePrivateData A pointer to a function that takes `**privateData` as a parameter.
+ *
+ * @return A pointer to a new `CCNxPortalStack`.
+ *
+ */
+CCNxPortalStack *
+ccnxPortalStack_Create(const CCNxPortalFactory *factory,
+ const CCNxPortalAttributes *attributes,
+ void (*start)(void *privateData),
+ void (*stop)(void *privateData),
+ CCNxMetaMessage *(*receive)(void *privateData, const CCNxStackTimeout *microSeconds),
+ bool (*send)(void *privateData, const CCNxMetaMessage *message, const CCNxStackTimeout *microSeconds),
+ bool (*listen)(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds),
+ bool (*ignore)(void *privateData, const CCNxName *name, const CCNxStackTimeout *microSeconds),
+ int (*getFileId)(void *privateData),
+ bool (*setAttributes)(void *privateData, const CCNxPortalAttributes *attributes),
+ CCNxPortalAttributes * (*getAttributes)(void *privateData),
+ void *privateData,
+ void (*releasePrivateData)(void **privateData));
+
+/**
+ * Increase the number of references to a `PARCBuffer`.
+ *
+ * Note that new `PARCBuffer` is not created,
+ * only that the given `PARCBuffer` reference count is incremented.
+ * Discard the reference by invoking `parcBuffer_Release`.
+ *
+ * @param [in] portal A pointer to a valid CCNxPortalStack instance.
+ *
+ * @return The input `CCNxPortalStack` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *x = parcBuffer_Allocate(10);
+ *
+ * PARCBuffer *x_2 = parcBuffer_Acquire(x);
+ *
+ * parcBuffer_Release(&x);
+ * parcBuffer_Release(&x_2);
+ * }
+ * @endcode
+ */
+CCNxPortalStack *ccnxPortalStack_Acquire(const CCNxPortalStack *portal);
+
+/**
+ * Release a previously acquired reference to the specified `CCNxPortalStack` 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] portalPtr A pointer to a pointer to a `CCNxPortalStack` instance to be released.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxPortalStack *stack = ccnxPortalStack_Create(...);
+ *
+ * ccnxPortalStack_Release(&stack);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxPortalStack_Create}
+ * @see {@link ccnxPortalStack_Acquire}
+ */
+void ccnxPortalStack_Release(CCNxPortalStack **portalPtr);
+
+/**
+ * Release a `CCNxPortalStack` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `CCNxPortalStack`.
+ *
+ * @param [in,out] instancePtr is a pointer to the `CCNxPortalStack` reference to be released.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void ccnxPortalStack_Release(CCNxPortalStack **instancePtr);
+
+/**
+ * Start a `CCNxPortalStack`
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`
+ *
+ * @return `true` if stack started successfully, else `false`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxPortalStack_Start(const CCNxPortalStack *implementation);
+
+/**
+ * Stop a `CCNxPortalStack`
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`
+ *
+ * @return `true` if stack started successfully, else `false`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxPortalStack_Stop(const CCNxPortalStack *implementation);
+
+/**
+ * Receive a message from a `CCNxPortalStack`
+ *
+ * @param [in] portalStack A pointer to an instance of `CCNxPortalStack`
+ * @param [in] microSeconds A pointer to a `struct timeval` or NULL indicating no timeout.
+ *
+ * @return An instance of {@link CCNxMetaMessage}.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxMetaMessage *ccnxPortalStack_Receive(const CCNxPortalStack *portalStack, const CCNxStackTimeout *microSeconds);
+
+/**
+ * Send a message through a `CCNxPortalStack`
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ * @param [in] portalMessage A pointer to an instance of `CCNxMetaMessage` to send.
+ *
+ * @return `true` if message sent successfully, else `false`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxPortalStack_Send(const CCNxPortalStack *implementation, const CCNxMetaMessage *portalMessage, const CCNxStackTimeout *microSeconds);
+
+/**
+ * Set the attributes on a `CCNxPortalStack`.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ * @param [in] attributes A pointer to an instance of `CCNxPortalAttributes`.
+ * @return `true` if attributes set successfully, else `false`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+bool ccnxPortalStack_SetAttributes(const CCNxPortalStack *implementation, const CCNxPortalAttributes *attributes);
+
+/**
+ * Get the attributes from a `CCNxPortalStack`.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ * @return A pointer to an instance of `CCNxPortalAttributes` associated with the @p implementation.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const CCNxPortalAttributes *ccnxPortalStack_GetAttributes(const CCNxPortalStack *implementation);
+
+/**
+ * Listen for @p name on the @p implementation.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ * @param [in] name A pointer to an instance of {@link CCNxName} to listen for.
+ *
+ * @return `true` if listen started successfully, else `false`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxPortalStack_Listen(const CCNxPortalStack *implementation, const CCNxName *name, const CCNxStackTimeout *microSeconds);
+/**
+ * Ignore (stop listening for) @p name on the @p implementation.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ * @param [in] name A pointer to an instance of {@link CCNxName} to listen for.
+ *
+ * @return `true` if ignore was successful, else `false`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+bool ccnxPortalStack_Ignore(const CCNxPortalStack *implementation, const CCNxName *name, const CCNxStackTimeout *microSeconds);
+/**
+ * Get the file ID for @p implementation.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ *
+ * @return `int` The file ID.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int ccnxPortalStack_GetFileId(const CCNxPortalStack *implementation);
+
+/**
+ * Get the {@link PARCKeyId} associated with the @p implementation.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ *
+ * @return A pointer to the `PARCKeyId`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const PARCKeyId *ccnxPortalStack_GetKeyId(const CCNxPortalStack *implementation);
+
+/**
+ * Get the error code for the most recent operation.
+ *
+ * @param [in] implementation A pointer to an instance of `CCNxPortalStack`.
+ *
+ * @return A value corresponding to the UNIX `errno` see `sys/errno.h`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+int ccnxPortalStack_GetErrorCode(const CCNxPortalStack *implementation);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCProperties *ccnxPortalStack_GetProperties(const CCNxPortalStack *portalStack);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] portalStack <#description#>
+ * @param [in] name <#description#>
+ * @param [in] defaultValue <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *ccnxPortalStack_GetProperty(const CCNxPortalStack *portalStack, const char *restrict name, const char *restrict defaultValue);
+#endif
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/.gitignore b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/.gitignore
new file mode 100644
index 00000000..ebc1afaf
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/.gitignore
@@ -0,0 +1,5 @@
+ccnx-portal-read
+ccnx-portal-write
+*.o
+ccnx_server
+ccnx_client
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/CMakeLists.txt b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/CMakeLists.txt
new file mode 100644
index 00000000..6d0a3f09
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/CMakeLists.txt
@@ -0,0 +1,19 @@
+set(CCNX_CLIENT_SRC
+ ccnx-client.c
+ ccnxPortalClient_About.c
+ )
+
+set(CCNX_SERVER_SRC
+ ccnx-server.c
+ ccnxPortalServer_About.c
+ )
+
+
+
+add_executable(ccnx-client ${CCNX_CLIENT_SRC})
+target_link_libraries(ccnx-client ${CCNX_LINK_LIBRARIES})
+
+add_executable(ccnx-server ${CCNX_SERVER_SRC})
+target_link_libraries(ccnx-server ${CCNX_LINK_LIBRARIES})
+
+install(TARGETS ccnx-client ccnx-server RUNTIME DESTINATION bin )
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-client.c b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-client.c
new file mode 100755
index 00000000..dfd5d5ba
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-client.c
@@ -0,0 +1,159 @@
+/*
+ * 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 <unistd.h>
+#include <getopt.h>
+
+#include <LongBow/runtime.h>
+
+#include "ccnxPortalClient_About.h"
+
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalRTA.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_IdentityFile.h>
+#include <parc/security/parc_PublicKeySigner.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_InputStream.h>
+#include <parc/algol/parc_OutputStream.h>
+
+int
+ccnGet(PARCIdentity *identity, CCNxName *name)
+{
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Message);
+
+ assertNotNull(portal, "Expected a non-null CCNxPortal pointer.");
+
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+
+ if (ccnxPortal_Send(portal, message, CCNxStackTimeout_Never)) {
+ while (ccnxPortal_IsError(portal) == false) {
+ CCNxMetaMessage *response = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ if (response != NULL) {
+ if (ccnxMetaMessage_IsContentObject(response)) {
+ CCNxContentObject *contentObject = ccnxMetaMessage_GetContentObject(response);
+
+ PARCBuffer *payload = ccnxContentObject_GetPayload(contentObject);
+
+ size_t length = parcBuffer_Remaining(payload);
+ ssize_t nwritten = write(1, parcBuffer_Overlay(payload, length), length);
+ assertTrue(nwritten == length, "Did not write whole buffer, got %zd expected %zu", nwritten, length);
+
+ break;
+ }
+ ccnxMetaMessage_Release(&response);
+ }
+ }
+ }
+
+ ccnxPortal_Release(&portal);
+
+ ccnxPortalFactory_Release(&factory);
+
+ return 0;
+}
+
+void
+usage(void)
+{
+ printf("%s\n", ccnxPortalClientAbout_About());
+ printf("ccn-client --identity <file> --password <password> <objectName>\n");
+ printf("ccn-client [-h | --help]\n");
+ printf("ccn-client [-v | --version]\n");
+ printf("\n");
+ printf(" --identity The file name containing a PKCS12 keystore\n");
+ printf(" --password The password to unlock the keystore\n");
+ printf(" <objectName> The LCI name of the object to fetch\n");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ char *keystoreFile = NULL;
+ char *keystorePassword = NULL;
+
+ /* options descriptor */
+ static struct option longopts[] = {
+ { "identity", required_argument, NULL, 'f' },
+ { "password", required_argument, NULL, 'p' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ int ch;
+ while ((ch = getopt_long(argc, argv, "fphv", longopts, NULL)) != -1) {
+ switch (ch) {
+ case 'f':
+ keystoreFile = optarg;
+ break;
+
+ case 'p':
+ keystorePassword = optarg;
+ break;
+
+ case 'v':
+ printf("%s\n", ccnxPortalClientAbout_Version());
+ return 0;
+
+ case 'h':
+ usage();
+ return 0;
+
+ default:
+ usage();
+ return -1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argv[0] == NULL || keystoreFile == NULL || keystorePassword == NULL) {
+ usage();
+ return -1;
+ }
+
+ char *objectName = argv[0];
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreFile, keystorePassword);
+ if (parcIdentityFile_Exists(identityFile) == false) {
+ printf("Inaccessible keystore file '%s'.\n", keystoreFile);
+ exit(1);
+ }
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ parcIdentityFile_Release(&identityFile);
+
+ CCNxName *name = ccnxName_CreateFromCString(objectName);
+
+ int result = ccnGet(identity, name);
+
+ parcIdentity_Release(&identity);
+ ccnxName_Release(&name);
+
+ return result;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-read.c b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-read.c
new file mode 100644
index 00000000..215d9019
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-read.c
@@ -0,0 +1,136 @@
+/*
+ * 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 <stdio.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_PublicKeySignerPkcs12Store.h>
+#include <parc/security/parc_IdentityFile.h>
+
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/common/ccnx_SignedInfo.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+#include <ccnx/common/ccnx_TimeStamp.h>
+
+PARCIdentity *
+getIdentity_FromFile(const char *keystoreFileName, const char *password)
+{
+ PARCIdentity *result = NULL;
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreFileName, password);
+ if (identityFile != NULL) {
+ result = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ parcIdentityFile_Release(&identityFile);
+ }
+
+ return result;
+}
+
+int
+reader_writer(CCNxPortalFactory *factory, const char *uri)
+{
+ CCNxPortal *portal = ccnxPortalFactory_GetInstance(factory, ccnxPortalTypeDatagram, ccnxPortalProtocol_TLV, &ccnxPortalAttributes_Blocking);
+
+ CCNxName *prefix = ccnxName_CreateFromURI(uri);
+ CCNxName *bye = ccnxName_CreateFromURI("lci:/Hello/Goodbye%21");
+ CCNxName *contentname = ccnxName_CreateFromURI("lci:/Hello/World");
+
+ if (ccnxPortal_Listen(portal, prefix, 365 * 86400, CCNxStackTimeout_Never)) {
+ CCNxMetaMessage *msg;
+
+ while ((msg = ccnxPortal_Receive(portal, CCNxStackTimeout_Never)) != NULL) {
+ if (ccnxMetaMessage_IsInterest(msg)) {
+ CCNxInterest *interest = ccnxMetaMessage_GetInterest(msg);
+
+ CCNxName *interestName = ccnxInterest_GetName(interest);
+
+ if (ccnxName_Equals(interestName, contentname)) {
+ const PARCKeyId *publisherKeyId = ccnxPortal_GetKeyId(portal);
+
+ char buffer[128];
+ time_t theTime = time(0);
+ sprintf(buffer, "Hello World. The time is %s", ctime(&theTime));
+
+ PARCBuffer *payload = parcBuffer_CreateFromArray(buffer, 128);
+ parcBuffer_Flip(payload);
+
+ PARCBuffer *b = parcBuffer_Acquire(payload);
+ CCNxContentObject *uob = ccnxContentObject_CreateWithNameAndPayload(contentname, b);
+
+ // missing NULL check, case 1024
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromContentObject(uob);
+ if (ccnxPortal_Send(portal, message, CCNxTransportStackTimeCCNxStackTimeout_Neverout_Never) == false) {
+ fprintf(stderr, "ccnx_write failed\n");
+ }
+ // ccnxMessage_Release(message);
+ } else if (ccnxName_Equals(interestName, bye)) {
+ break;
+ }
+ } else {
+ ccnxMetaMessage_Display(msg, 0);
+ }
+ ccnxMetaMessage_Release(&msg);
+ }
+ }
+
+ ccnxName_Release(&prefix);
+ ccnxName_Release(&bye);
+ ccnxName_Release(&contentname);
+
+ ccnxPortal_Release(&portal);
+
+ return 0;
+}
+
+int
+ccnx_Portal_Reader(char *keystoreFileName, const char *password, const char *uri)
+{
+ parcSecurity_Init();
+
+ PARCIdentity *identity = getIdentity_FromFile(keystoreFileName, password);
+
+ if (identity != NULL) {
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+
+ reader_writer(factory, uri);
+
+ ccnxPortalFactory_Release(&factory);
+ parcIdentity_Release(&identity);
+ }
+
+ parcSecurity_Fini();
+
+ return 0;
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ char *keystoreFileName = argv[1];
+ char *password = argv[2];
+ char *uri = argv[3];
+
+ keystoreFileName = "/tmp/keystore";
+ password = "password";
+ uri = "lci:/Hello";
+
+ // read fileName password lci://my/name lci
+ return ccnx_Portal_Reader(keystoreFileName, password, uri);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-write.c b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-write.c
new file mode 100755
index 00000000..2bb8aadf
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-portal-write.c
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+// Needs to be implemented, case 1037
+int
+main(int argc, char *argv[argc])
+{
+ return 0;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-server.c b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-server.c
new file mode 100755
index 00000000..a9d7a2e6
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnx-server.c
@@ -0,0 +1,218 @@
+/*
+ * 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 <time.h>
+
+#include <getopt.h>
+#include <stdio.h>
+
+#include "ccnxPortalServer_About.h"
+
+#include <ccnx/api/ccnx_Portal/ccnx_Portal.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalRTA.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_IdentityFile.h>
+
+#include <ccnx/common/ccnx_Name.h>
+
+extern PARCBuffer *makePayload(const CCNxName *interestName, const char *commandString);
+extern int ccnServe(const PARCIdentity *identity, const CCNxName *listenName, const char *commandString);
+extern void usage(void);
+
+PARCBuffer *
+makePayload(const CCNxName *interestName, const char *commandString)
+{
+ char *commandToExecute;
+
+ char *nameAsString = ccnxName_ToString(interestName);
+ int failure = asprintf(&commandToExecute, commandString, nameAsString);
+ assertTrue(failure > -1, "Error asprintf");
+ parcMemory_Deallocate((void **) &nameAsString);
+
+ PARCBufferComposer *accumulator = parcBufferComposer_Create();
+
+ FILE *fp = popen(commandToExecute, "r");
+ if (fp != NULL) {
+ unsigned char buffer[1024];
+
+ while (feof(fp) == 0) {
+ size_t length = fread(buffer, sizeof(char), sizeof(buffer), fp);
+ parcBufferComposer_PutArray(accumulator, buffer, length);
+ }
+ pclose(fp);
+ } else {
+ parcBufferComposer_PutString(accumulator, "Cannot execute: ");
+ parcBufferComposer_PutString(accumulator, commandString);
+ }
+
+ PARCBuffer *payload = parcBufferComposer_ProduceBuffer(accumulator);
+ parcBufferComposer_Release(&accumulator);
+
+ return payload;
+}
+
+int
+ccnServe(const PARCIdentity *identity, const CCNxName *listenName, const char *commandString)
+{
+ parcSecurity_Init();
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Message);
+ assertNotNull(portal, "Expected a non-null CCNxPortal pointer.");
+
+ if (ccnxPortal_Listen(portal, listenName, 365 * 86400, CCNxStackTimeout_Never)) {
+ while (true) {
+ CCNxMetaMessage *request = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+
+ if (request == NULL) {
+ break;
+ }
+
+ CCNxInterest *interest = ccnxMetaMessage_GetInterest(request);
+
+ if (interest != NULL) {
+ CCNxName *interestName = ccnxInterest_GetName(interest);
+
+ PARCBuffer *payload = makePayload(interestName, commandString);
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(interestName, payload);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromContentObject(contentObject);
+ if (ccnxPortal_Send(portal, message, CCNxStackTimeout_Never) == false) {
+ fprintf(stderr, "ccnxPortal_Write failed: %d\n", ccnxPortal_GetError(portal));
+ }
+ {
+ char *name = ccnxName_ToString(interestName);
+ time_t theTime = time(0);
+ char *time = ctime(&theTime);
+ printf("%24.24s %s\n", time, name);
+ parcMemory_Deallocate((void **) &name);
+ }
+
+ parcBuffer_Release(&payload);
+ }
+ ccnxMetaMessage_Release(&request);
+ }
+ }
+
+ ccnxPortal_Release(&portal);
+
+ ccnxPortalFactory_Release(&factory);
+
+ parcSecurity_Fini();
+
+ return 0;
+}
+
+void
+usage(void)
+{
+ printf("ccnx-server --identity <file> --password <password> lci:/ccn-name command-to-execute\n");
+ printf("ccnx-server [-h | --help]\n");
+ printf("ccnx-server [-v | --version]\n");
+ printf("\n");
+ printf(" --identity The file name containing a PKCS12 keystore\n");
+ printf(" --password The password to unlock the keystore\n");
+ printf(" lci:/ccn-name The LCI name of the object fetch\n");
+ printf(" program-to-execute The program to run (eg. /bin/date)\n");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ char *keystoreFile = NULL;
+ char *keystorePassword = NULL;
+ char *commandString = "/bin/date";
+ char *listenName = "lci:/Server";
+
+ /* options descriptor */
+ static struct option longopts[] = {
+ { "identity", required_argument, NULL, 'f' },
+ { "password", required_argument, NULL, 'p' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ if (argc < 2) {
+ usage();
+ exit(1);
+ }
+
+ int ch;
+ while ((ch = getopt_long(argc, argv, "fphvc:", longopts, NULL)) != -1) {
+ switch (ch) {
+ case 'f':
+ keystoreFile = optarg;
+ break;
+
+ case 'p':
+ keystorePassword = optarg;
+ break;
+
+ case 'v':
+ printf("%s\n", ccnxPortalServerAbout_Version());
+ return 0;
+
+ case 'h':
+ usage();
+ return 0;
+
+ default:
+ usage();
+ return -1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argv[0] == NULL || keystoreFile == NULL || keystorePassword == NULL) {
+ usage();
+ return -1;
+ }
+ listenName = argv[0];
+ commandString = argv[1];
+ argc += 2;
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreFile, keystorePassword);
+
+ if (parcIdentityFile_Exists(identityFile) == false) {
+ printf("Inaccessible keystore file '%s'.\n", keystoreFile);
+ exit(1);
+ }
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ parcIdentityFile_Release(&identityFile);
+
+ CCNxName *name = ccnxName_CreateFromCString(listenName);
+
+ int result = ccnServe(identity, name, commandString);
+
+ ccnxName_Release(&name);
+
+ return result;
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.c b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.c
new file mode 100644
index 00000000..ff9465f8
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T10:25:45Z
+
+#include "ccnxPortalClient_About.h"
+
+const char *ccnxPortalClient_What = "@(#)" "CCNx Portal Client " RELEASE_VERSION " 2017-02-22T13:21:28.462492"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+ccnxPortalClientAbout_Name(void)
+{
+ return "CCNx Portal Client";
+}
+
+const char *
+ccnxPortalClientAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+ccnxPortalClientAbout_About(void)
+{
+ return "CCNx Portal Client "RELEASE_VERSION " 2017-02-22T13:21:28.462492" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalClientAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalClientAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalClientAbout_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-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.h b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.h
new file mode 100755
index 00000000..df0c625d
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalClient_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T10:25:45Z
+
+#ifndef ccnxPortalClient_About_h
+#define ccnxPortalClient_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *ccnxPortalClient_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *ccnxPortalClientAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *ccnxPortalClientAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *ccnxPortalClientAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *ccnxPortalClientAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *ccnxPortalClientAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *ccnxPortalClientAbout_LongNotice(void);
+
+#endif // ccnxPortalClient_About_h
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.c b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.c
new file mode 100644
index 00000000..6596e1bd
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T10:25:45Z
+
+#include "ccnxPortalServer_About.h"
+
+const char *ccnxPortalServer_What = "@(#)" "CCNx Portal Server " RELEASE_VERSION " 2017-02-22T13:21:39.498237"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+ccnxPortalServerAbout_Name(void)
+{
+ return "CCNx Portal Server";
+}
+
+const char *
+ccnxPortalServerAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+ccnxPortalServerAbout_About(void)
+{
+ return "CCNx Portal Server "RELEASE_VERSION " 2017-02-22T13:21:39.498237" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalServerAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalServerAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxPortalServerAbout_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-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.h b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.h
new file mode 100755
index 00000000..fd95f81f
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/command-line/ccnxPortalServer_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T10:25:45Z
+
+#ifndef ccnxPortalServer_About_h
+#define ccnxPortalServer_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *ccnxPortalServer_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *ccnxPortalServerAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *ccnxPortalServerAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *ccnxPortalServerAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *ccnxPortalServerAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *ccnxPortalServerAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *ccnxPortalServerAbout_LongNotice(void);
+
+#endif // ccnxPortalServer_About_h
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/config.h.in b/libccnx-portal/ccnx/api/ccnx_Portal/config.h.in
new file mode 100644
index 00000000..0c02e279
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/config.h.in
@@ -0,0 +1,3 @@
+//CCNx Portal defines
+
+#define _GNU_SOURCE
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/.gitignore b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/.gitignore
new file mode 100644
index 00000000..34eb8191
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/.gitignore
@@ -0,0 +1,6 @@
+*.aux
+*.out
+*.toc
+*.synctex.gz
+*.texpadtmp
+CCNTransportStackPortal.pdf
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Abstract.tex b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Abstract.tex
new file mode 100644
index 00000000..ffa6f8f1
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Abstract.tex
@@ -0,0 +1,9 @@
+%-
+% ABSTRACT
+%-
+%
+\Abstract{
+The CCN Transport Stack is a software framework that provides facilities for orchestrating the transmission and reception of CCN messages.
+The design of the Transport Stack permits a high degree of configurability enabling different capabilities and behaviors as needed. The CCN Portal API is a programmatic mechanism to create, maintain and use multiple CCN Transport Stacks, each associated with a specific Portal instance.
+Each CCN Portal instance provides a simple programming interface to an associated CCN Transport Stack.
+} \ No newline at end of file
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/CCNTransportStackPortal.tex b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/CCNTransportStackPortal.tex
new file mode 100644
index 00000000..9cb0458a
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/CCNTransportStackPortal.tex
@@ -0,0 +1,46 @@
+% A PARC specific refinement of:
+%
+% Stylish Article
+% LaTeX Template
+% Version 2.0 (13/4/14)
+%
+% This template has been downloaded from:
+% http://www.LaTeXTemplates.com
+%
+% Original author:
+% Mathias Legrand (legrand.mathias@gmail.com)
+%
+% License:
+% CC BY-NC-SA 3.0 (http://creativecommons.org/licenses/by-nc-sa/3.0/)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%-
+% PACKAGES AND OTHER DOCUMENT CONFIGURATIONS
+%-
+
+\documentclass[fleqn,10pt]{PARCTwoColumn} % Document font size and equations flushed left
+
+%-
+% COLUMNS
+%-
+
+\setlength{\columnsep}{0.55cm} % Distance between the two columns of text
+\setlength{\fboxrule}{0.75pt} % Width of the border around the abstract
+
+%-
+% HYPERLINKS
+%-
+
+\definecolor{color1}{RGB}{0,0,90}
+\definecolor{color2}{RGB}{0,20,20}
+\usepackage{hyperref} % Required for hyperlinks
+\hypersetup{hidelinks,colorlinks,breaklinks=true,urlcolor=color2,citecolor=color1,linkcolor=color1,bookmarksopen=false,pdftitle={Title},pdfauthor={Author}}
+%
+\input{Packages}
+%
+\input{Title}
+%
+\input{Abstract}
+%
+\input{Document}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Document.tex b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Document.tex
new file mode 100644
index 00000000..b17c33e4
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Document.tex
@@ -0,0 +1,501 @@
+\begin{document}
+
+\flushbottom % Makes all text pages the same height
+
+\maketitle % Print the title and abstract box
+
+\tableofcontents % Print the contents section
+
+\thispagestyle{empty} % Removes page numbering from the first page
+
+%-
+% ARTICLE CONTENTS
+%-
+
+\section{Overview} % The \section*{} command stops section numbering
+\addcontentsline{toc}{section}{Introduction} % Adds this section to the table of contents
+This document describes the basic client software required to transmit and receive CCN messages
+via CCN Forwarders on a CCN Network. As shown in Figure 1, an application may use the Portal API to manipulate
+the Transport Stack to send and receive messages on a CCN network.
+
+ \begin{figure}[ht]
+\center{\includegraphics[width=205pt]{StackDiagram}}
+\caption{Transport Stack ({\it typ.\/})}
+\end{figure}
+
+
+The Transport Stack is composed of a set of components, each focused on a specific task. Typical stacks include components
+for CCN Flow Control, outbound message signing, inbound message signature verification,
+packet format encoding and decoding, fragmentation and reassembly, and CCN Forwarder communication.
+The extensible architecture supports stacks from the very primitive, providing only mandatory features such as datagram-style message sending and receiving, to the highly sophisticated, providing optional features such as an in-order stream of Content Objects with arbitrary rewind and fast-forward within the stream. Different Transport Stacks may include different features of different implementations of the same
+features.
+
+The Portal API provides a simple interface to the Transport Stack allowing the application to compose, use, and maintain Transport Stacks and to perform message operations through the stack. Each Portal API instance is associated with a specific CCN Transport Stack.
+It is a low-level API providing a simple interface upon which applications and other interfaces are implemented. Examples of higher level services that could leverage the Portal API include the CCN Assembly Framework, the CCN Key-Value Store API, and the CCN Message Queue API.
+
+Together, the Portal API and its associated Transport Stack provide the basic mechanism for sending and receiving CCN messages. These Messages contain Interests, Content Objects, and Control messages.
+Interests and Content Objects are the primary elements of discourse in CCN,
+while Control messages govern the operation of various network elements.
+Taken together, the combination of Portal API associated with a Stack is called a Portal instance.
+The Portal instance is a library of functions that perform operations between the API and the Stack.
+The CCN Portal library creates, maintains, and uses CCN Portal API instances.
+
+\section{Requirements}
+
+\subsection {The Transport Stack}
+The Transport Stack must:
+\begin{itemize}
+\item provide a full interface for the CCN Portal API to access.
+
+\item isolate specific technical concerns into distinct functional components with different experimental and non-experimental implementations.
+
+\item isolate implementation details for encoding and decoding of network packets,
+signing and verification,fragmentation and reassembly, flow and rate control from the application's concern.
+
+\item be able to easily interface with multiple kinds of CCN Forwarder implementations.
+
+\item be easily extensible and a good platform for experimentation.
+\end{itemize}
+
+\subsection {Portal API}
+Each Portal API must:
+
+\begin{itemize}
+\item be able to compose,
+instantiate, associate with, and ultimately use a single
+Transport Stack instantiation using the Transport Framework API.
+
+\item be bound to an identity representing the Portal API instance and its Transport Stack.
+
+\item provide transmission and reception of individual CCN Messages (e.g. Interest, Content Object, and Control messages).
+
+\item provide support for the establishing and abolishing in-bound reception of CCN Messages based upon a CCN Name.
+
+\item provide a facility to set and get attributes related to the state and operation of the Portal instance and its associated Stack. Attributes include:
+\begin{itemize}
+\item an indication of whether dynamically modifiable blocking or non-blocking modes of reception and transmission are used.
+
+\item an indication that a stack will no longer provide or accept inbound or outbound CCN Messages.
+\end{itemize}
+
+\end{itemize}
+\section{Transport Stack}
+The Transport Stack is a component based piece of software following the chain-of-command pattern. It manages two message queues:
+\begin{itemize}
+\item An outbound queue moving messages from the application toward the network.
+\item An inbound queue moving messages from the network toward the application.
+\end{itemize}
+
+As shown in figure 1, The Transport Stack is composed of a set of optional components and two required components: the API Adaptor and the Forwarder Adaptor. Messages are pipelined through the Transport Stack components on their way between the Portal API and the Forwarder. Possible stack components might include elements to handle fragmentation, codecs to translate a programmatic representation of a message into a properly encoded packet, flow control components to manage prefetching, or any other component implemented by a third party. The Transport Stack is designed to be extensible such that an application can utilize as simple or as a sophisticated set of components as it needs.
+
+An application uses the Portal API instance to create, manipulate, and use a Transport Stack.
+The Portal API sends and receives messages through the Transport Stack's API Adaptor.
+
+\subsection{Transport Stack Names}
+The Portal API can reference its own Transport Stack by the name "localstack" in order to set or get properties in the Transport Stack's management information database. This name is valid only within the scope of a single Transport Stack.
+
+A Transport Stack may also have a name assigned to it by its Forwarder Adaptor.
+This name distinguishes one Transport Stack from another within the scope of a single Forwarder.
+
+\subsection{Transport Stack Components}
+A Transport Stack is composed of a set of components through which messages flow in both inbound and outbound directions.
+Each component focuses on a single purpose, thus maintaining a separation of concerns between elements in the stack, and enabling a
+plug-and-play approach to stack composition for different needs.
+
+The following descriptions illustrate typical components in the Transport Stack.
+It is not an exhaustive list, and only the API adaptor and Forwarder Adaptor are required.
+
+\subsubsection{API Adaptor}
+The API adaptor is a required component providing the interface
+between the stack and the application's Portal instance.
+At a minimum, it translates messages between the execution environments of the application and the stack.
+
+\subsubsection{Flow Control}
+The Flow Control component is an optional component
+responsible for managing the flow of outbound and inbound messages to
+ensure in-order delivery, retransmission, sequential fetching and prefetching of messages.
+
+\subsubsection{Codec}
+The Codec component translates a programmatic form of a message into a properly formatted packet suitable for transmission and vice-versa.
+
+The message signature computed over the formatted byte array requires the Codec component to have access to encryption keys for signing and verification.
+This access is provided to the Codec component in any way suitable for the implementation.
+For example, a Codec component implementation might use an identity framework external to the Stack,
+it might participate in a protocol to fetch identity information from the network,
+or it might simply be provided with the identity information from the Portal API via a Control message.
+
+\subsubsection{Fragmentation}
+Fully formatted packets may exceed the size of a maximum transfer unit and as a consequence
+must be fragmented for transmission.
+Similarly, when fragments are received, they must be reassembled into fully formed packets.
+
+\subsubsection{Forwarder Adaptor}
+The Forwarder Adaptor is a required component providing the interface between the Stack and the CCN Forwarder.
+The Forwarder Adaptor is responsible for establishing an association with a CCN Forwarder
+and interacting with the Forwarder to transmit and receive network packets.
+
+For example, a Forwarder implementation may execute on a computer and communicate with all of the Forwarder Adaptors via an IPC mechanism.
+In this case, the Forwarder Adaptor establishes the IPC channel with the Forwarder.
+Similarly, the Forwarder may provide administrative controls out-of-band from the packets it receives. In this case the Forwarder Adaptor is responsible for using those out-of-band controls as necessary.
+
+\subsection{Future}
+The Transport Stack architecture is illustrative but not entirely prescriptive.
+Over time, we expect that well-known, canonical, stack ensembles will emerge
+that are no longer concerned with extensibility or experimentation.
+It would be reasonable to implement such ensembles in as few components as necessary, to promote consistency and ease-of-use.
+Nevertheless, even those omnibus components should be designed with the same requirements for separation of concerns and ease of extensibility or maintenance in mind.
+
+\section{Transport Framework}
+The Transport Framework is responsible for supplying the runtime environment for a Transport Stack.
+It provides an interface for composing and decomposing Transport Stacks and interfaces with the
+necessary system resources (e.g. the operating system, communication interfaces, etc.). While an application
+may start multiple Portal instances with associated Transport Stacks, it will only have one Transport Framework
+to manage all stacks.
+
+\begin{figure}[ht]
+\center{\includegraphics[width=205pt]{TransportStackFramework}}
+\caption{A Transport Framework with multiple, different Transport Stacks.}
+\end{figure}
+
+\section{Portal Instances}
+When a Portal instance is created, it is immediately associated with a Transport Stack
+*{\it under the auspices of a specific identity}.
+
+In this case, the identity is a digital representation of an entity such as an individual, an organization,
+an administrative function, etc.
+The identity should not be confused with a CCN {\it Name} which is a label for something to which messages can be sent, although in some cases
+CCN Named entities may also serve as the identity context of a Portal instance.
+
+\noindent\fbox{\parbox{\textwidth/2 -5\fboxsep-2\fboxrule}{
+{\it *This identity represents the creator of the Stack, which may not necessarily represent the user of the stack.
+For example, an administrative function may create a specific Stack using an administrative identity,
+providing necessary authentication to other services that assist in the creation of the Stack
+then delegate the use of the Stack to an application that does not possess those administrative credentials.}}}
+
+During the course of the Stack's creation and its binding with the Portal instance,
+the Stack acquires a unique CCN LCI name colloquially called "{\tt localstack}". This uniquely identifies the Portal-Stack assembly.
+As a matter of convenience, a specific label from the Labeled Content Information schema is used as shorthand for {\tt localstack}.
+
+A CCN Transport Stack is comprised of multiple components forming a chain-of-command pattern to send and receive CCN messages.
+The formulation of a Stack is prescribed by the Portal instance itself when it is created. For example, Portal instances providing message-by-message-like behavior will create and associate with a Transport Stack providing such behavior;
+Portal instances providing in-order delivery of Content Object messages, being triggered by an initial Interest message,
+will create and associate with a Transport Stack containing components to implement that behavior.
+
+When the life of a CCN Portal instance has ended,
+it is released by its application and resources are deallocated by the operating environment's runtime normally.
+
+Application interactions with the Portal instance consist of invoking methods to send or receive CCN Messages, get or set meta-data regarding the state of the Portal instance.
+
+\subsection{Portal Attributes}
+Transport Stacks are composed of multiple components,
+ each with potentially different attributes that together
+indicate the current state of the stack.
+Each Portal instance maintains a common interface to these attributes.
+
+Some attributes are read-only (for example, a flow control component will signal the state of the flow in a read only attribute),
+while others may be modified only by their specific component (for example, the application specifies blocking or non-blocking modes
+through a read-write attribute).
+
+
+\subsubsection{Queueing Modes}
+
+\begin{enumerate}
+\item {\bf Blocking}
+The client of the Portal instance will block on operations that require a Message to be sent or received if sufficient resources are unavailable.
+\item {\bf Non-blocking}
+The client of the Portal instance will not block on operations that require a Message to be sent or received earn sufficient resources are unavailable.
+\end{enumerate}
+
+
+\subsection{Methods}
+Once a Portal instance is created,
+CCN Messages are sent and received via the appropriate API methods as listed below.
+
+\subsubsection{Send}
+
+The {\tt Send} method enqueues a CCN Message on the outbound queue.
+
+If the queuing mode of the Portal instance is non-blocking and the outbound queue is full,
+this method will fail and signal failure without changing the state of the Portal instance.
+
+If the queuing mode of the Portal instance is blocking and the outbound queue is full,
+this function will block until it is able to successfully enqueue the Message to send.
+
+\subsubsection{Receive}
+
+The {\tt Receive} method dequeues a CCN Message from the inbound queue in the Transport Stack.
+
+If the queuing mode of the Portal instance is non-blocking and the inbound queue is empty,
+this method will fail and signal a temporary failure.
+
+If the queuing mode of the Portal instance is blocking and the inbound queue is empty,
+this function will block until it is able to successfully dequeue a Message to send. {\bf should this be receive?}
+
+\subsubsection{Get Identity}
+Return the Identity associated with the Portal instance.
+
+\subsubsection{Set Identity}
+Set the Identity associated with the Portal instance.
+Setting the Identity does not change the name of the Portal instance. {\bf what is the name?}
+
+\subsubsection{Get Attribute}
+Fetch the value of a named attribute maintained by the Portal instance and its associated Transport Stack.
+
+\subsubsection{Set Attribute}
+Set the value of a named attribute maintained by the Portal instance and its associated Transport Stack.
+The Set is a compare-and-swap wherein a predicate value for the attribute is supplied and if the predicate value
+is equal to the current value of the attribute,
+the attribute value is set to the new value.
+
+\subsubsection{Listen}
+A convenience method that sends the correct Control message to cause CCN Interests with Names starting with a specific prefix to be enqueued in the Transport Stack input queue.
+This operation may require authorization. {\bf why is this a convenience method? Isn't listening and ignoring the main thing to do? who provides authorization}
+
+\subsubsection{Ignore}
+A convenience method that send the correct Control message to cause CCN Interests for Names starting with a specific prefix to not be enqueued in the Transport Stack input queue.
+
+\section{CCN Messages}
+CCN Messages are Interests, Content Objects, and Control messages.
+Each messages contains a CCN Name that directs where the message is sent.
+For example, a CCN Interest message follows the path defined in the Forwarding Information Base (FIB) and deposits an entry in the Pending Interest Table (PIT) of the Forwarder.
+A CCN Content Object messages follows the reverse path specified in the PIT entry and consumes the entry.
+
+\subsection{Interest}
+An Interest is a CCN Message requesting the CCN Content Object message (matching the Name specified in the Interest message) as a response.
+
+\subsection{Content Object}
+
+A Content Object is a CCN Message response to a received CCN Message request.
+
+\subsection{Control}
+Control messages direct the operation of the Portal instance,
+the Transport Stack, and the local Forwarder. They are delivered in the order received by the API or Forwarder Adaptors.
+
+Control Messages are directed to a specific component in a stack by including the LCI name of the component in the message. The Name is a composite of the stack name and the name of a component. For example, a message addressed to the Name {\tt lci:/localstack/codec} would be directed to the {\tt codec} component in the Transport Stack. Every Control message request results in a Control message response. The following section outline a typical set of messages for various Transport Stack components.
+
+{\it
+Notifications as we have them now are just Control messages "up-side-down,"
+or "inbound" rather than outbound.
+A notification is just an unexpected inbound message signalling some state change or information
+(usually after the fact).
+Similarly the control messages are outbound,
+just as unexpected and signal some state change or information
+(usually before the fact).
+So a notification can just be a Control message going the other way.
+
+If we do away with special messages for notifications and special cases for their behavior,
+and reuse the Control Message as both an outbound and inbound message, then the inbound (notification) would require a response.
+But that could be a function of the Portal API library which,
+when it receives an inbound control message always responds with an ACK,
+plus it maintains a representation of the state of the Stack anyway so this is good.
+
+That would have interesting effects:
+I could formulate a control message in my application.
+Send it via Portal down my Transport Stack, through the forwarder to another stack.
+That stack would then receive my control message, possibly act upon it and send a reply.
+Yes I'm skipping over the authorization and authentication part,
+I expect them to be there but I don't expect to always have to describe them.
+
+But at this point, it looks like a CCN Interest again.
+So control messages and notifications just more Interests and Content Objects?
+Or they are Interests and Content Objects with special cased behavior?
+}
+
+
+{\it I make a distinction between Control Messages that affect the stack those that may be transmitted on the network. This is only for clarity at the moment, it may be that they are the same thing, just distinguished by "scope."}
+
+\section{Control Messages for Stack Components}
+\subsection{API Adaptor Control Messages}
+{\tt lci:/localstack/api}
+
+\subsubsection{Pause}
+Cause the API Adaptor and each component subsequently receiving this message
+on the outbound-side of the Stack to not accept any new outbound messages.
+The Forwarder Adaptor must reply to this message and prohibit the enqueing
+of any new inbound message.
+The Forwarder Adaptor's reply indicates to each inbound component
+to not accept any new inbound messages that are not reply messages.
+
+\subsubsection{Resume}
+Cause the API adaptor and each subsequent component to accept new outbound messages,
+The Forwarder Adaptor must reply to this message and enable the enqueing of new inbound messages.
+The Forwarder Adaptor's reply indicates to each inbound component to accept new inbound messages.
+
+\subsubsection{GetAttributes}
+Get the attributes of the API Adaptor Component.
+
+\subsection{Flow Control Control Messages}
+{\tt lci:/localstack/flowcontrol}
+
+The Flow Control component manages the transmission and reception of data comprised of many,
+in-order messages.
+
+A flow is started as the result of the Flow Control component
+receiving an Interest message with the Name containing a valid chunked specification.
+The current position of the flow is set to the value of the chunk
+specified and the limit is set to infinity.
+
+{\it Need a way to name a flow.}
+
+\subsubsection{StartFlow}
+Signal the Flow Control component to start a flow from a specific position to a limit.
+When the flow reaches the limit,
+an inbound message is enqueued signaling that the flow terminated because it reached the limit.
+If the flow terminates before reaching the limit,
+an inbound notification message is enqueued signaling that the flow terminated normally.
+
+\subsubsection{GetPosition}
+Get the current position of the specified flow.
+
+\subsubsection{SetLimit}
+Signal the Flow Control component to immediately set the current limit to the given value.
+The limit can never be set less than the current position.
+
+\subsubsection{GetLimit}
+Get the current limit of the flow.
+
+\paragraph{StopFlow}
+Signal the Flow Control component to immediately stop a flow.
+
+\subsubsection{GetAttributes}
+Get the attributes of the Flow Control Component.
+
+\subsection{Signing Component Control Messages}
+{\tt lci:/localstack/signing}
+
+\subsubsection{SetKey}
+Set the signing key for all subsequent messages.
+
+\subsubsection{UnsetKey}
+Remove the signing key for all subsequent messages.
+Depending upon the implementation behavior of the Signing Component,
+this may cause unsigned messages to be transmitted,
+or the Signing Component may block and signal errors until a new key has been set.
+
+\subsubsection{GetAttributes}
+Get the attributes of the Signing Component.
+
+\subsection{Verification Component Control Messages}
+{\tt lci:/localstack/verification}
+
+\subsubsection{AddKey}
+Add a verification key to the set of keys for valid inbound messages.
+
+\subsubsection{DeleteKey}
+Delete a verification key from the set of keys for valid inbound messages.
+
+\subsubsection{GetAttributes}
+Get the attributes of the Verification Component.
+
+\subsection{Fragmentation Component Control Messages}
+{\tt lci:/localstack/fragmentation}
+
+\subsubsection{GetFragmentSize}
+Get the current Fragment Size used by the Fragmentation Component.
+
+\subsubsection{SetFragmentSize}
+Set the current Fragment Size used by the Fragmentation Component.
+
+\subsubsection{GetAttributes}
+Get the attributes of the Fragmentation Component.
+
+\subsection{Forwarder Adapter Control Messages}
+{\tt lci:/localstack/forwarder}
+
+\subsubsection{CreateRoute}
+Create a FIB entry for the given name to a specified interface.
+The entry must not already exist.
+This operation may require authorization.
+
+\subsubsection{ReadRoute}
+Fetch the FIB entry for the given name.
+If the name does not exist, the reply indicates failure.
+This operation may require authorization.
+
+\subsubsection{UpdateRoute}
+Modify an existing FIB entry for a given name.
+An existing FIB entry must already exist.
+This operation may require authorization.
+
+\subsubsection{DeleteRoute}
+Delete an existing FIB entry for a given name.
+If the name does not exist, the reply indicates failure.
+This operation may require authorization.
+
+\subsubsection{GetRoutes}
+Fetch information about all of the FIB entries in the Forwarder visible by this Portal Stack.
+This operation may require authorization.
+
+\subsubsection{GetInterfaces}
+Fetch information about all interfaces visible by this Portal Stack.
+This operation may require authorization.
+
+\subsubsection{Listen}
+Direct the Forwarder to forward CCN Interests with names starting with a specific prefix to this Portal Stack.
+The Forwarder adaptor enqueues these messages in the Transport Stack input queue.
+This operation may require authorization.
+
+\subsubsection{GetAttributes}
+Get the attributes of the Forwarder Adaptor.
+
+\subsubsection{Ignore}
+Direct the Forwarder to not forward CCN Interests with names starting with a specific prefix to this Portal Stack.
+
+
+%
+%\subsubsection{Request}
+%Request Control messages are either a query or a query/update for state and configuration information for the one or more network elements.
+%
+%For example, a Control message could request the KeyId used by Portal and its associated stack for signing outbound Content Objects.
+%Similarly, a Control message can request the KeyId used by Portal and its associated stack to be changed.
+%
+%\subsubsection{Response}
+%Every Request Control Message produces a Response Control Message which is sent upwards to the Portal to be either read and interpreted by the Portal API implementation, or passed to the client of the Portal API for processing.
+%A Response Control Message indicates either success or failure of the original Request Control Message.
+%
+%\subsubsection{Close}
+%
+%\subsubsection{Add Route}
+%
+%\subsubsection{Add Route To This Stack}
+%
+%%------------------------------------------------
+%
+%\section{Implementation}
+%
+%A CCN Portal instance is created either by the CCN Portal Factory,
+%which is a generator of CCN Portal API instances sharing a common set of attributes held by the factory,
+%or by creating the CCN Portal API instance directly by calling its creation method.
+%
+%\section{Discussion}
+%
+%\subsubsection{Multiple Identities}
+%An example use has been noted where there is a single Portal on which
+%Content Objects to send are to be signed by different keys.
+%A prerequisite for this is for the signing component in the Transport Stack to change the key used to sign Content Objects as they are encoded.
+%
+%Thus, the Portal use would consist of sending a Control Message setting the signing key and sending Content Objects.
+%When a Content Object must be sent signed by a different key, the application uses Portal to send a Control Message setting the new signing key and sending the Content Objects.
+%
+%This has an impact on the semantics and implementation of {\tt GetKeyId} for the Portal instance.
+%For example, does GetKeyId return the KeyId of the current KeyId being used by the Transport Stack's signing component, or does it return the in the most recent Change Key Control message?
+%
+
+%------------------------------------------------
+%\phantomsection
+%\section*{Acknowledgments} % The \section*{} command stops section numbering%
+%
+%\addcontentsline{toc}{section}{Acknowledgments} % Adds this section to the table of contents
+
+
+
+%----------------------------------------------------------------------------------------
+% REFERENCE LIST
+%----------------------------------------------------------------------------------------
+\phantomsection
+%\bibliographystyle{unsrt}
+%\bibliography{sample}
+
+%----------------------------------------------------------------------------------------
+
+\end{document}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/PARCTwoColumn.cls b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/PARCTwoColumn.cls
new file mode 100644
index 00000000..33fe7d29
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/PARCTwoColumn.cls
@@ -0,0 +1,280 @@
+% A PARC specific refinement of:
+%
+% Stylish Article
+% LaTeX Template
+% Version 2.0 (13/4/14)
+%
+% Available from:
+% http://www.LaTeXTemplates.com
+%
+% Original author:
+% Mathias Legrand (legrand.mathias@gmail.com)
+%
+% License:
+% CC BY-NC-SA 3.0 (http://creativecommons.org/licenses/by-nc-sa/3.0/)
+% ---------------------------------------------------------------------
+% Conference proceedings and article templates for
+% personal open-archiving activities
+% September 2012
+% ---------------------------------------------------------------------
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{PARCTwoColumn}[25/01/2012, v1.0]
+\RequirePackage{ifthen}
+\RequirePackage{calc}
+\AtEndOfClass{\RequirePackage{microtype}}
+\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}
+\ProcessOptions*
+\LoadClass{article}
+\RequirePackage{ifpdf} % Needed to pick between latex and pdflatex
+
+%----------------------------------------------------------------------
+% FONTS
+%----------------------------------------------------------------------
+
+%\RequirePackage{times} % Loads the Times-Roman Fonts
+\RequirePackage{palatino} % Loads the Palatino Fonts
+%\RequirePackage{mathptmx} % Loads the Times-Roman Math Fonts
+
+%----------------------------------------------------------------------
+% VARIOUS USEFUL PACKAGES
+%----------------------------------------------------------------------
+
+\RequirePackage[utf8]{inputenc}
+\RequirePackage{amsmath,amsfonts,amssymb}
+\RequirePackage{graphicx,xcolor}
+\RequirePackage[english]{babel}
+\RequirePackage{booktabs}
+\RequirePackage{multicol}
+\RequirePackage{tabularx}
+
+%----------------------------------------------------------------------
+% MARGINS
+%----------------------------------------------------------------------
+
+\RequirePackage[left=2cm,%
+ right=2cm,%
+ top=2.25cm,%
+ bottom=2.25cm,%
+ headheight=11pt,%
+ letterpaper]{geometry}%
+
+%----------------------------------------------------------------------
+% FIGURES AND TABLES CAPTIONS
+%----------------------------------------------------------------------
+
+\RequirePackage[labelfont={bf,sf,small},%
+ labelsep=period,%
+ justification=raggedright]{caption}
+\setlength{\abovecaptionskip}{0pt}
+\setlength{\belowcaptionskip}{0pt}
+
+%----------------------------------------------------------------------
+% PARC Colors
+%----------------------------------------------------------------------
+
+\definecolor{PARCBlue}{RGB}{32,84,105}
+\definecolor{PARCDarkBlue}{RGB}{0,35,50}
+\definecolor{PARCLightBlue}{RGB}{58,110,143}
+\definecolor{PARCOrange}{RGB}{255,102,0}
+\definecolor{PARCLightGray}{RGB}{213,213,213}
+\definecolor{PARCDarkGray}{RGB}{58,58,58}
+
+\definecolor{AbstractBackgroundColor}{RGB}{58,110,143}
+
+\definecolor{SectionColor}{RGB}{0,0,90} % Color of the article title and sections
+%
+%----------------------------------------------------------------------
+% PAGE HEADER
+%----------------------------------------------------------------------
+%
+\RequirePackage{fancyhdr} % Needed to define custom headers/footers
+\headheight=13.6pt
+\RequirePackage{lastpage} % Number of pages in the document
+\pagestyle{fancy} % Enables the custom headers/footers
+% Headers
+\lhead{}%
+\chead{}%
+\rhead{\small\sffamily\bfseries\@PaperTitle\ --- \thepage/\pageref{LastPage}}
+% Footers
+\lfoot{}%
+\cfoot{}%
+\rfoot{}%
+\renewcommand{\headrulewidth}{0pt}% % No header rule
+\renewcommand{\footrulewidth}{0pt}% % No footer rule
+
+%----------------------------------------------------------------------
+% SECTION/SUBSECTION/PARAGRAPH SET-UP
+%----------------------------------------------------------------------
+
+\RequirePackage[explicit]{titlesec}
+\titleformat{\section}
+ {\color{PARCDarkBlue}\large\sffamily\bfseries}
+ {}
+ {0em}
+ {\colorbox{PARCDarkBlue!10}{\parbox{\dimexpr\linewidth-2\fboxsep\relax}{\centering\arabic{section}. #1}}}
+ []
+\titleformat{name=\section,numberless}
+ {\color{PARCDarkBlue}\large\sffamily\bfseries}
+ {}
+ {0em}
+ {\colorbox{PARCDarkBlue!10}{\parbox{\dimexpr\linewidth-2\fboxsep\relax}{\centering#1}}}
+ []
+\titleformat{\subsection}
+ {\color{PARCDarkBlue}\sffamily\bfseries}
+ {\thesubsection}
+ {0.5em}
+ {#1}
+ []
+\titleformat{\subsubsection}
+ {\sffamily\small\bfseries}
+ {\thesubsubsection}
+ {0.5em}
+ {#1}
+ []
+\titleformat{\paragraph}[runin]
+ {\sffamily\small\bfseries}
+ {}
+ {0em}
+ {#1}
+\titlespacing*{\section}{0pc}{3ex \@plus4pt \@minus3pt}{5pt}
+\titlespacing*{\subsection}{0pc}{2.5ex \@plus3pt \@minus2pt}{0pt}
+\titlespacing*{\subsubsection}{0pc}{2ex \@plus2.5pt \@minus1.5pt}{0pt}
+\titlespacing*{\paragraph}{0pc}{1.5ex \@plus2pt \@minus1pt}{10pt}
+
+%----------------------------------------------------------------------
+% TABLEOFCONTENTS SET-UP
+%----------------------------------------------------------------------
+\newlength{\tocsep}
+\setlength\tocsep{2em} % Sets the indentation of the sections in the table of contents
+\setcounter{tocdepth}{3} % Three levels in the table of contents section: sections, subsections and subsubsections
+
+\usepackage{titletoc}
+\contentsmargin{0cm}
+\titlecontents{section}[\tocsep]
+ {\addvspace{4pt}\small\bfseries\sffamily}
+ {\contentslabel[\thecontentslabel]{\tocsep}}
+ {}
+ {\hfill\thecontentspage}
+ []
+\titlecontents{subsection}[\tocsep]
+ {\addvspace{2pt}\sffamily}
+ {\contentslabel[\thecontentslabel]{\tocsep}}
+ {}
+ {\ \titlerule*[.5pc]{.}\ \thecontentspage}
+ []
+\titlecontents*{subsubsection}[\tocsep]
+ {\footnotesize\sffamily}
+ {}
+ {}
+ {}
+ [\ \textbullet\ ]
+
+%----------------------------------------------------------------------
+% MULTIPLE AUTHOR SET
+%----------------------------------------------------------------------
+
+\newcount\@authcnt
+\newcount\@tmpcnt\@tmpcnt\z@
+
+\def\@affiliation{%
+ \ifnum\@tmpcnt<\@authcnt
+ \global\advance\@tmpcnt1
+ \raggedright \csname @auth\romannumeral\the\@tmpcnt\endcsname\hfill\\%
+ \let\next\@affiliation \vskip1pt
+ \else
+ \let\next\relax
+ \fi
+\next}
+
+\newcommand{\affiliation}[1]{%
+ \global\advance\@authcnt1
+ \expandafter\gdef\csname @auth\romannumeral\the\@authcnt\endcsname
+ {#1}}
+
+
+%----------------------------------------------------------------------
+% LIST CONTROL
+%----------------------------------------------------------------------
+
+\RequirePackage{enumitem}
+%\setlist{nolistsep} % Uncomment to remove spacing between items in lists (enumerate, itemize)
+
+%----------------------------------------------------------------------
+% ABSTRACT+AUTHOR FRAME
+%----------------------------------------------------------------------
+
+\newcommand{\PaperTitle}[2]{\def\@PaperTitle{#1}\def\@PaperSubtitle{#2}}
+\newcommand{\Archive}[1]{\def\@Archive{#1}}
+\newcommand{\Authors}[1]{\def\@Authors{#1}}
+\newcommand{\JournalInfo}[1]{\def\@JournalInfo{#1}}
+\newcommand{\Abstract}[1]{\def\@Abstract{#1}}
+\newcommand{\Keywords}[1]{\def\@Keywords{#1}}
+\newcommand{\Masthead}[1]{\def\@Masthead{#1}}
+%
+% ---------------------------------------------------------------------
+%
+\newcommand{\NormalSansBold}[1]{\normalsize\sffamily\bfseries #1}
+\newcommand{\SmallSansBold}[1]{\small\sffamily\bfseries #1}
+\newcommand{\MastHeadText}[1]{\sffamily\bfseries\fontsize{12}{14.4}\selectfont #1}
+%
+\newcommand{\MakePARCMastHead}[1]{
+\setlength{\tabcolsep}{0pt}
+\begin{tabular*}{\textwidth}{l @{\extracolsep{\fill}} p{0.618\textwidth} }
+ \includegraphics[width=140pt]{parc_black_solid}&\vbox{\raggedleft\MastHeadText{#1}\vskip0.5mm}\\
+\end{tabular*}
+}
+%
+\newcommand{\MakeTitle}[2]{%
+{\raggedright\color{SectionColor}\sffamily\bfseries\fontsize{22}{25}\selectfont #1\par}%
+{\raggedright\color{SectionColor}\sffamily\bfseries\fontsize{16}{24}\selectfont #2\par}%
+}
+%
+\newcommand{\MakeAbstract}[2]{%
+\parbox{\textwidth-6\fboxsep-2\fboxrule}{%
+\ifx\@Keywords\@empty%
+\sffamily\textbf{\abstractname}\\#1%
+\else%
+\sffamily\textbf{\abstractname}\\#1\\[4pt]%
+\textbf{\keywordname}\\#2%
+\fi%
+}%
+}%
+%
+\renewcommand{\@maketitle}{%
+\twocolumn[{%
+\thispagestyle{empty}%
+\MakePARCMastHead{\@Masthead}%
+\vskip30pt%
+\MakeTitle{\@PaperTitle}{\@PaperSubtitle}%
+\vskip10pt%
+{\raggedright\color{SectionColor}\sffamily\fontsize{12}{16}\selectfont\@Authors\par}%
+\vskip18pt%
+\fcolorbox{SectionColor}{white}{%
+\parbox{\textwidth-2\fboxsep-2\fboxrule}{\centering%
+\colorbox{AbstractBackgroundColor!10}{%
+\MakeAbstract{\@Abstract}{\@Keywords}
+}%
+\vskip4pt%
+\begingroup%
+\raggedright\sffamily\small%
+\footnotesize\@affiliation\par%
+\endgroup%%
+}%
+}%
+\vskip25pt%
+}]%
+}%
+
+%----------------------------------------------------------------------
+% REFERENCES
+%----------------------------------------------------------------------
+
+% Remove brackets from numbering in List of References
+\renewcommand{\@biblabel}[1]{\bfseries\color{SectionColor}\textsuperscript{[#1]}}
+%\setlength{\bibitemsep}{0cm}
+\let\oldbibliography\thebibliography
+\renewcommand{\thebibliography}[1]{%
+\addcontentsline{toc}{section}{\refname}%
+\oldbibliography{#1}%
+\setlength\itemsep{0pt}}%
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Packages.tex b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Packages.tex
new file mode 100644
index 00000000..b09403e8
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Packages.tex
@@ -0,0 +1,46 @@
+%
+% Specify packages that you need in this file.
+% If a package requires configuration, do that here.
+\usepackage{lipsum}
+
+\usepackage{tikz}
+\usetikzlibrary{shadows,arrows}
+% Define the layers to draw the diagram
+\pgfdeclarelayer{background}
+\pgfdeclarelayer{foreground}
+\pgfsetlayers{background,main,foreground}
+
+% Define block styles
+\tikzstyle{materia}=[draw, fill=blue!20, text width=6.0em, text centered,
+ minimum height=1.5em,drop shadow]
+\tikzstyle{component} = [materia, text width=9em, minimum width=10em,
+ minimum height=3em, rounded corners, drop shadow]
+\tikzstyle{texto} = [above, text width=6em, text centered]
+\tikzstyle{linepart} = [draw, thick, color=black!50, -latex', dashed]
+\tikzstyle{line} = [draw, thick, color=black!50, -latex']
+\tikzstyle{ur}=[draw, text centered, minimum height=0.01em]
+
+% Define distances for bordering
+\newcommand{\blockdist}{1.3}
+\newcommand{\edgedist}{1.5}
+
+\newcommand{\component}[3]{node (p#1) [component]%
+ {#2\\{\scriptsize\textit{#3}}}}
+
+% Draw background
+\newcommand{\background}[5]{%
+ \begin{pgfonlayer}{background}
+ % Left-top corner of the background rectangle
+ \path (#1.west |- #2.north)+(-0.5,0.5) node (a1) {};
+ % Right-bottom corner of the background rectangle
+ \path (#3.east |- #4.south)+(+0.5,-0.25) node (a2) {};
+ % Draw the background
+ \path[fill=orange!10,rounded corners, draw=black!50, dashed]
+ (a1) rectangle (a2);
+ \path (a1.east |- a1.south)+(0.8,-0.3) node (u1)[texto]
+ {\scriptsize\textit{#5}};
+ \end{pgfonlayer}}
+
+\newcommand{\transreceptor}[3]{%
+ \path [linepart] (#1.east) -- node [above]
+ {\scriptsize Transreceptor #2} (#3);}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/README.md b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/README.md
new file mode 100644
index 00000000..7d6de0e0
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/README.md
@@ -0,0 +1,16 @@
+# PARC-Two-Column-modular
+An modular template consisting of a single TeX class file (`PARCTwoColumn.cls`), a single TeX source file driving the inclusion of several subsidiary files.
+Consider using this template when the document may need to be included in other layouts,
+keeping the layout separate from content.
+
+A the layout is two columns per page.
+
+To use this template, copy the entire set of files to your own directory that will contain the document.
+
+Modify the following files according to your needs
+
+| :----------- | -------------------: |
+| `Abstract.tex` | The Abstract section of the first page. |
+| `Document.tex` | The entire \begin{document} ... \end{document} segment. |
+| `Packages.tex` | Include required packages and their configurations. |
+| `Title.tex` | The content of the Masthead and Title on the first page. |
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Stack Diagram.graffle b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Stack Diagram.graffle
new file mode 100644
index 00000000..838445c7
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Stack Diagram.graffle
Binary files differ
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/StackDiagram.pdf b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/StackDiagram.pdf
new file mode 100644
index 00000000..7d67e5a4
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/StackDiagram.pdf
Binary files differ
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Title.tex b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Title.tex
new file mode 100644
index 00000000..c67da1d7
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/Title.tex
@@ -0,0 +1,15 @@
+%----------------------------------------------------------------------------------------
+% ARTICLE INFORMATION
+%----------------------------------------------------------------------------------------
+\Masthead{Networking and Distributed Systems\\Computing Science Laboratory\\Copyright 2014, PARC Confidential}
+
+\PaperTitle{CCN Transport Stack and Portal API}{} % Article title
+
+\Authors{Glenn Scott\textsuperscript{1}*} % Authors
+\affiliation{\textsuperscript{1}\textit{Computing Science Laboratory, PARC}} % Author affiliation
+\affiliation{*\textbf{Corresponding author}: glenn.scott@parc.com} % Corresponding author
+
+\Keywords{Keyword1 --- Keyword2 --- Keyword3} % Keywords - if you don't want any simply remove all the text between the curly brackets
+\newcommand{\keywordname}{Keywords} % Defines the keywords heading name
+
+\rfoot{PARC Confidential}% \ No newline at end of file
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/TransportStackFramework.pdf b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/TransportStackFramework.pdf
new file mode 100644
index 00000000..2e78bd03
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/TransportStackFramework.pdf
Binary files differ
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/parc_black_solid.png b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/parc_black_solid.png
new file mode 100644
index 00000000..6abcf2f4
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/parc_black_solid.png
Binary files differ
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/documentation/sample.bib b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/sample.bib
new file mode 100644
index 00000000..fdd186c9
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/documentation/sample.bib
@@ -0,0 +1,8 @@
+@ARTICLE{Figueredo:2009dg,
+ author = {Figueredo, A.~J. and Wolf, P. S.~A.},
+ title = {Assortative pairing and life history strategy - a cross-cultural study.},
+ journal = {Human Nature},
+ volume = {20},
+ pages = {317-330},
+ year = {2009}
+} \ No newline at end of file
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/.gitignore b/libccnx-portal/ccnx/api/ccnx_Portal/test/.gitignore
new file mode 100644
index 00000000..1d17bd28
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/.gitignore
@@ -0,0 +1,9 @@
+my_keystore
+test_ccnx_Portal
+test_ccnx_PortalAPI
+test_ccnx_PortalFactory
+test_ccnx_PortalImplementation
+test_ccnx_PortalImplementation_keystore
+test_ccnx_PortalStack
+test_ccnx_PortalRTA
+test_ccnx_PortalAnchor
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/CMakeLists.txt b/libccnx-portal/ccnx/api/ccnx_Portal/test/CMakeLists.txt
new file mode 100644
index 00000000..88ce6f1a
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_ccnx_Portal
+ test_ccnx_PortalFactory
+ test_ccnx_PortalStack
+ test_ccnx_PortalAPI
+ test_ccnx_PortalRTA
+ test_ccnx_PortalAnchor
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/LOG b/libccnx-portal/ccnx/api/ccnx_Portal/test/LOG
new file mode 100644
index 00000000..b12907ad
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/LOG
@@ -0,0 +1,25 @@
+Tue Nov 17 11:07:47 PST 2015
+test_ccnx_Portal: 2 fixtures
+test_ccnx_Portal/Global: Ran 15 test cases. 100% (15) succeeded
+test_ccnx_Portal/Global/ccnxPortal_Open 1.003460s 0.000000s 0.000000s 58088 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Open_NonBlocking 1.004843s 0.000000s 0.000000s 7633 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Send 1.005196s 0.000000s 0.000000s 9095 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_GetStatus 1.005718s 0.000000s 0.000000s 8515 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_GetError 1.001110s 0.000000s 0.000000s 9675 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_GetFileId 1.004810s 0.000000s 0.000000s 9326 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Listen 1.005183s 0.000000s 0.000000s 11009 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Ignore 1.002009s 0.000000s 0.000000s 12281 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_GetKeyId 1.004295s 0.000000s 0.000000s 6628 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_IsEOF 1.001509s 0.000000s 0.000000s 8789 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_IsError 1.001177s 0.000000s 0.000000s 9116 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Receive_NeverTimeout 1.004686s 0.000000s 0.000000s 14333 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Receive_ImmediateTimeout 3.005053s 0.000000s 0.000000s 22072 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Receive_ImmediateTimeout_NoData 1.003191s 0.000000s 0.000000s 6700 Succeeded
+test_ccnx_Portal/Global/ccnxPortal_Receive_5SecondTimeout 6.005013s 0.000000s 0.000000s 16884 Succeeded
+test_ccnx_Portal/Performance: Ran 3 test cases. 100% (3) succeeded
+test_ccnx_Portal/Performance/ccnxPortalFactory_CreatePortal 4.504010s 0.000000s 0.000000s 4582325 Succeeded
+test_ccnx_Portal/Performance/ccnxPortal_Send 23.504715s 0.000000s 0.000000s 92851121 Succeeded
+test_ccnx_Portal/Performance/ccnxPortal_SendReceive 1.004153s 0.000000s 0.000000s 11961 Succeeded
+Program ended with exit code: 0
+
+
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_Portal.c b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_Portal.c
new file mode 100644
index 00000000..154b8be8
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_Portal.c
@@ -0,0 +1,826 @@
+/*
+ * 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_Portal.c"
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <stdio.h>
+#include <sys/errno.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalRTA.h>
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAPI.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+#include <parc/developer/parc_Stopwatch.h>
+
+#include <ccnx/transport/test_tools/bent_pipe.h>
+
+#include <parc/security/parc_IdentityFile.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+
+//#define USE_APILOOPBACK
+
+#ifdef USE_APILOOPBACK
+# define TEST_STACK ccnxPortalAPI_LoopBack
+#else
+# define TEST_STACK ccnxPortalRTA_LoopBack
+#endif
+
+LONGBOW_TEST_RUNNER(test_ccnx_Portal /*, .requires="FeatureLongBowSubProcess"*/)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+#define perTestCase
+
+LONGBOW_TEST_RUNNER_SETUP(test_ccnx_Portal)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(test_ccnx_Portal)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Open);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Open_NonBlocking);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Send);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_GetStatus);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_GetError);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_GetFileId);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Listen);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Ignore);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_GetKeyId);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_IsEOF);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_IsError);
+
+// LONGBOW_RUN_TEST_CASE(Global, Hello);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Receive_NeverTimeout);
+// LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Receive_NeverTimeout_Hang);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Receive_ImmediateTimeout);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Receive_ImmediateTimeout_NoData);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Receive_5SecondTimeout);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Send_NeverTimeout);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Send_ImmediateTimeout);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortal_Send_ImmediateTimeout_WouldBlock);
+}
+
+static uint32_t InitialMemoryOutstanding = 0;
+
+typedef struct test_data {
+ BentPipeState *bentpipe;
+ CCNxPortalFactory *factory;
+} TestData;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ InitialMemoryOutstanding = parcMemory_Outstanding();
+ if (InitialMemoryOutstanding != 0) {
+ printf("Global fixture setup has outstanding allocations %u\n", InitialMemoryOutstanding);
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ }
+
+ TestData *data = parcMemory_Allocate(sizeof(TestData));
+
+ char bent_pipe_name[1024];
+ static const char bent_pipe_format[] = "/tmp/test_ccnx_Portal%d.sock";
+ sprintf(bent_pipe_name, bent_pipe_format, getpid());
+ unlink(bent_pipe_name);
+ setenv("BENT_PIPE_NAME", bent_pipe_name, 1);
+
+ data->bentpipe = bentpipe_Create(bent_pipe_name);
+ bentpipe_Start(data->bentpipe);
+
+ unsigned int keyLength = 1024;
+ unsigned int validityDays = 30;
+ char *subjectName = "test_ccnx_Portal";
+
+ parcSecurity_Init();
+
+ bool success = parcPkcs12KeyStore_CreateFile("my_keystore", "my_keystore_password", subjectName, keyLength, validityDays);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('my_keystore', 'my_keystore_password') failed.");
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create("my_keystore", "my_keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ parcIdentityFile_Release(&identityFile);
+
+ data->factory = ccnxPortalFactory_Create(identity);
+ parcIdentity_Release(&identity);
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ sleep(2);
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxPortalFactory_Release(&data->factory);
+
+ bentpipe_Stop(data->bentpipe);
+ bentpipe_Destroy(&data->bentpipe);
+
+ parcMemory_Deallocate((void **) &data);
+ unsetenv("BENT_PIPE_NAME");
+ parcSecurity_Fini();
+
+ if (parcMemory_Outstanding() != InitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("('%s' leaks memory by %d\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - InitialMemoryOutstanding);
+// return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+char *keyStoreFileName = "/tmp/test_ccnx_Portal.keystore";
+char *keyStorePassWord = "password";
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Open)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ parcObjectTesting_AssertAcquire(portal);
+
+ ccnxPortal_Release(&portal);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Open_NonBlocking)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+
+ parcObjectTesting_AssertAcquire(portal);
+
+ ccnxPortal_Release(&portal);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Send)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+ bool actual = ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+
+ ccnxMetaMessage_Release(&message);
+ ccnxInterest_Release(&interest);
+
+ ccnxPortal_Release(&portal);
+
+ assertTrue(actual, "Expected ccnxPortal_Send to be successful.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_GetStatus)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+
+ const CCNxPortalStatus *status = ccnxPortal_GetStatus(portal);
+
+ ccnxMetaMessage_Release(&message);
+ ccnxInterest_Release(&interest);
+
+ ccnxPortal_Release(&portal);
+
+ assertNotNull(status, "Expected non-null result from ccnxPortal_GetStatus");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_GetError)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+
+ const int error = ccnxPortal_GetError(portal);
+
+ ccnxMetaMessage_Release(&message);
+ ccnxInterest_Release(&interest);
+
+ ccnxPortal_Release(&portal);
+
+ assertTrue(error == 0, "Expected 0 result from ccnxPortal_GetError");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_GetFileId)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+ ccnxInterest_Release(&interest);
+
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+ int fileId = ccnxPortal_GetFileId(portal);
+ assertTrue(fileId != -1, "Expected ccnxPortal_GetFileId to not return -1");
+ ccnxPortal_Release(&portal);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_IsEOF)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+
+ bool actual = ccnxPortal_IsEOF(portal);
+
+ ccnxInterest_Release(&interest);
+ ccnxMetaMessage_Release(&message);
+
+ ccnxPortal_Release(&portal);
+
+ assertFalse(actual, "Expected to not be at EOF");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_IsError)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+
+ bool actual = ccnxPortal_IsError(portal);
+
+ ccnxMetaMessage_Release(&message);
+ ccnxInterest_Release(&interest);
+
+ ccnxPortal_Release(&portal);
+
+ assertFalse(actual, "Expected not to have an error status");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Listen)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ bool actual = ccnxPortal_Listen(portal, name, 60, CCNxStackTimeout_Never);
+
+ ccnxName_Release(&name);
+
+ ccnxPortal_Release(&portal);
+
+ assertTrue(actual, "Expected ccnxPortal_Listen to return true");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Ignore)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ bool actual = ccnxPortal_Ignore(portal, name, CCNxStackTimeout_Never);
+ ccnxName_Release(&name);
+
+ ccnxPortal_Release(&portal);
+
+ assertTrue(actual, "Expected ccnxPortal_Ignore to return true");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_GetKeyId)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ const PARCKeyId *actual = ccnxPortal_GetKeyId(portal);
+ const PARCKeyId *expected = ccnxPortalFactory_GetKeyId(data->factory);
+
+ ccnxPortal_Release(&portal);
+
+ assertTrue(parcKeyId_Equals(actual, expected), "Expected the PARCKeyId instances to be equal.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Send_NeverTimeout)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalOut = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+ ccnxInterest_Release(&interest);
+
+ if (ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Never)) {
+ ccnxMetaMessage_Release(&interestMessage);
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+ }
+
+ ccnxPortal_Release(&portalIn);
+ ccnxPortal_Release(&portalOut);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Send_ImmediateTimeout)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalOut = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+ ccnxInterest_Release(&interest);
+
+ if (ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Immediate)) {
+ ccnxMetaMessage_Release(&interestMessage);
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+ }
+
+ ccnxPortal_Release(&portalIn);
+ ccnxPortal_Release(&portalOut);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Send_ImmediateTimeout_WouldBlock)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalOut = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+
+ for (int count = 0; count < 10000; count++) {
+ if (ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Immediate) == false) {
+ break;
+ }
+ count++;
+ }
+
+ assertFalse(ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Immediate),
+ "Expected send to fail due to blocking");
+
+ ccnxMetaMessage_Release(&interestMessage);
+ ccnxInterest_Release(&interest);
+ ccnxPortal_Release(&portalOut);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Receive_NeverTimeout)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalOut = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+ ccnxInterest_Release(&interest);
+
+ if (ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Never)) {
+ ccnxMetaMessage_Release(&interestMessage);
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+ }
+
+ ccnxPortal_Release(&portalIn);
+ ccnxPortal_Release(&portalOut);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Receive_NeverTimeout_Hang)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+ ccnxPortal_Release(&portalIn);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Receive_ImmediateTimeout)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalOut = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+
+ if (ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Never)) {
+ sleep(2);
+ ccnxMetaMessage_Release(&interestMessage);
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Immediate);
+
+ assertTrue(ccnxInterest_Equals(interest, ccnxMetaMessage_GetInterest(message)), "Expected Interest to be received.");
+ ccnxMetaMessage_Release(&message);
+ }
+
+ ccnxInterest_Release(&interest);
+ ccnxPortal_Release(&portalIn);
+ ccnxPortal_Release(&portalOut);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Receive_ImmediateTimeout_NoData)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ ccnxPortal_Receive(portalIn, CCNxStackTimeout_Immediate);
+ assertTrue(errno == ENOMSG, "Expected errno to be set to ENOMSG, actual %s", strerror(errno));
+
+ ccnxPortal_Release(&portalIn);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortal_Receive_5SecondTimeout)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ ccnxPortal_Receive(portalIn, CCNxStackTimeout_MicroSeconds(5000000));
+ assertTrue(errno == ENOMSG, "Expected errno to be set to ENOMSG, actual %s", strerror(errno));
+
+ ccnxPortal_Release(&portalIn);
+}
+
+LONGBOW_TEST_CASE(Global, Hello)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ CCNxPortal *portalIn = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ assertNotNull(portal, "Expected a non-null CCNxPortal pointer.");
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+
+ if (ccnxPortal_Send(portal, interestMessage, CCNxStackTimeout_Never)) {
+ for (int responses = 0; responses == 0; ) {
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Never);
+ if (message != NULL) {
+ if (ccnxMetaMessage_IsContentObject(message)) {
+ CCNxContentObject *contentObject = ccnxMetaMessage_GetContentObject(message);
+
+ PARCBuffer *payload = ccnxContentObject_GetPayload(contentObject);
+ if (parcBuffer_HasRemaining(payload) == false) {
+ fprintf(stderr, "**************** Content object has arrived WITH EMPTY CONTENT\n");
+ } else {
+ char *string = parcBuffer_ToString(payload);
+ fprintf(stderr, "**************** Content object has arrived: %s\n", string);
+ parcMemory_Deallocate((void **) &string);
+ }
+ responses++;
+ }
+ ccnxMetaMessage_Release(&message);
+ }
+ }
+ }
+
+ ccnxMetaMessage_Release(&interestMessage);
+ ccnxPortal_Release(&portal);
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, ccnxPortal_SendReceive);
+ LONGBOW_RUN_TEST_CASE(Performance, ccnxPortalFactory_CreatePortal);
+ LONGBOW_RUN_TEST_CASE(Performance, ccnxPortal_Send);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ InitialMemoryOutstanding = parcMemory_Outstanding();
+
+ TestData *data = parcMemory_Allocate(sizeof(TestData));
+
+ char bent_pipe_name[1024];
+ static const char bent_pipe_format[] = "/tmp/test_ccnx_Portal%d.sock";
+ sprintf(bent_pipe_name, bent_pipe_format, getpid());
+ setenv("BENT_PIPE_NAME", bent_pipe_name, 1);
+
+ data->bentpipe = bentpipe_Create(bent_pipe_name);
+ bentpipe_Start(data->bentpipe);
+
+ longBowTestRunner_SetClipBoardData(testRunner, data->bentpipe);
+
+ unsigned int keyLength = 1024;
+ unsigned int validityDays = 30;
+ char *subjectName = "test_ccnx_Comm";
+
+ parcSecurity_Init();
+
+ bool success = parcPkcs12KeyStore_CreateFile("my_keystore", "my_keystore_password", subjectName, keyLength, validityDays);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('my_keystore', 'my_keystore_password') failed.");
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create("my_keystore", "my_keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ parcIdentityFile_Release(&identityFile);
+
+ data->factory = ccnxPortalFactory_Create(identity);
+ parcIdentity_Release(&identity);
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ ccnxPortalFactory_Release(&data->factory);
+ bentpipe_Stop(data->bentpipe);
+ bentpipe_Destroy(&data->bentpipe);
+ parcMemory_Deallocate((void **) &data);
+ unsetenv("BENT_PIPE_NAME");
+ parcSecurity_Fini();
+
+ if (parcMemory_Outstanding() != InitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("('%s' leaks memory by %d\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - InitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, ccnxPortalFactory_CreatePortal)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ for (int i = 0; i < 1000; i++) {
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ ccnxPortal_Release(&portal);
+ }
+}
+
+LONGBOW_TEST_CASE(Performance, ccnxPortal_Send)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ for (int i = 0; i < 100000; i++) {
+ ccnxPortal_Flush(portal, CCNxStackTimeout_Never);
+ }
+
+ ccnxPortal_Release(&portal);
+}
+
+typedef struct parc_ewma {
+ bool initialized;
+ int64_t value;
+ double coefficient;
+} PARCEWMA;
+
+PARCEWMA *
+parcEWMA_Create(double coefficient)
+{
+ PARCEWMA *result = parcMemory_AllocateAndClear(sizeof(PARCEWMA));
+ if (result != NULL) {
+ result->initialized = false;
+ result->value = 0;
+ result->coefficient = coefficient;
+ }
+
+ return result;
+}
+
+void
+parcEWMW_Destroy(PARCEWMA **ewma)
+{
+ parcMemory_Deallocate(ewma);
+}
+
+int64_t
+parcEWMA_Update(PARCEWMA *ewma, int64_t value)
+{
+ if (ewma->initialized) {
+ ewma->value = ((value + ewma->coefficient * ewma->value - ewma->value) / ewma->coefficient);
+ } else {
+ ewma->value = value;
+ ewma->initialized = true;
+ }
+ return ewma->value;
+}
+
+int64_t
+parcEWMA_GetValue(const PARCEWMA *ewma)
+{
+ return ewma->value;
+}
+
+static uint64_t
+sendx(CCNxPortal *portalOut, uint32_t index, const CCNxName *name)
+{
+ PARCStopwatch *timer = parcStopwatch_Create();
+
+ parcStopwatch_Start(timer);
+
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+
+ PARCBuffer *payload = parcBuffer_Allocate(sizeof(uint64_t) + sizeof(uint32_t));
+ parcBuffer_PutUint32(payload, index);
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ uint64_t theTime = tv.tv_sec * 1000000 + tv.tv_usec;
+ parcBuffer_PutUint64(payload, theTime);
+ parcBuffer_Flip(payload);
+
+ ccnxInterest_SetPayload(interest, payload);
+
+ CCNxMetaMessage *interestMessage = ccnxMetaMessage_CreateFromInterest(interest);
+
+ ccnxPortal_Send(portalOut, interestMessage, CCNxStackTimeout_Never);
+
+ parcBuffer_Release(&payload);
+
+ ccnxMetaMessage_Release(&interestMessage);
+ ccnxInterest_Release(&interest);
+
+ uint64_t result = parcStopwatch_ElapsedTimeNanos(timer);
+ parcStopwatch_Release(&timer);
+ return result;
+}
+
+static void *
+sender(void *data)
+{
+ CCNxPortal *portalOut = data;
+
+ PARCEWMA *ewma = parcEWMA_Create(0.75);
+ CCNxName *name = ccnxName_CreateFormatString("lci:/local/trace");
+
+ for (uint32_t i = 300; i != 0; i--) {
+ uint64_t elapsedTime = sendx(portalOut, i, name);
+ parcEWMA_Update(ewma, elapsedTime);
+ }
+ uint64_t elapsedTime = sendx(portalOut, 0, name);
+ parcEWMA_Update(ewma, elapsedTime);
+
+ printf("sender %9" PRId64 " us/message\n", parcEWMA_GetValue(ewma));
+
+ parcEWMW_Destroy(&ewma);
+ ccnxName_Release(&name);
+ return 0;
+}
+
+static void *
+receiver(void *data)
+{
+ CCNxPortal *portalIn = data;
+
+ uint32_t index;
+ PARCEWMA *ewma = parcEWMA_Create(0.75);
+ PARCEWMA *roundTrip = parcEWMA_Create(0.75);
+
+ PARCStopwatch *timer = parcStopwatch_Create();
+ do {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ uint64_t theTime = tv.tv_sec * 1000000 + tv.tv_usec;
+
+ parcStopwatch_Start(timer);
+ CCNxMetaMessage *message = ccnxPortal_Receive(portalIn, CCNxStackTimeout_Never);
+
+ PARCBuffer *payload = ccnxInterest_GetPayload(ccnxMetaMessage_GetInterest(message));
+
+ index = parcBuffer_GetUint32(payload);
+
+ parcEWMA_Update(roundTrip, theTime - parcBuffer_GetUint64(payload));
+
+ parcEWMA_Update(ewma, parcStopwatch_ElapsedTimeNanos(timer));
+
+ ccnxMetaMessage_Release(&message);
+ } while (index != 0);
+
+ printf("receiver %9" PRId64 " us/message %9" PRId64 " us\n", parcEWMA_GetValue(ewma), parcEWMA_GetValue(roundTrip));
+
+ parcStopwatch_Release(&timer);
+ parcEWMW_Destroy(&roundTrip);
+ parcEWMW_Destroy(&ewma);
+
+ return 0;
+}
+
+LONGBOW_TEST_CASE(Performance, ccnxPortal_SendReceive)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxPortal *portalSend = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+ CCNxPortal *portalReceive = ccnxPortalFactory_CreatePortal(data->factory, TEST_STACK);
+
+ pthread_t thread_receiver1;
+ pthread_t thread_sender;
+ pthread_create(&thread_receiver1, NULL, receiver, portalReceive);
+ pthread_create(&thread_sender, NULL, sender, portalSend);
+
+ pthread_join(thread_receiver1, NULL);
+
+ ccnxPortal_Flush(portalSend, CCNxStackTimeout_Never);
+ ccnxPortal_Flush(portalReceive, CCNxStackTimeout_Never);
+ ccnxPortal_Release(&portalSend);
+ ccnxPortal_Release(&portalReceive);
+ sleep(2);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_ccnx_Portal);
+ int exitStatus = longBowMain(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAPI.c b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAPI.c
new file mode 100755
index 00000000..736e6982
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAPI.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 "../ccnx_Portal.c"
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalAPI.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <parc/security/parc_IdentityFile.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+
+LONGBOW_TEST_RUNNER(test_ccnx_PortalAPI /*, .requires="FeatureLongBowSubProcess"*/)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(test_ccnx_PortalAPI)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(test_ccnx_PortalAPI)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalAPI_CreateRelease);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalAPI_SendReceive);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalAPI_GetFileId);
+}
+
+static size_t InitialMemoryOutstanding = 0;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ InitialMemoryOutstanding = parcMemory_Outstanding();
+
+ unsigned int keyLength = 1024;
+ unsigned int validityDays = 30;
+ char *subjectName = "test_ccnx_Comm";
+
+ parcSecurity_Init();
+
+ bool success = parcPkcs12KeyStore_CreateFile("my_keystore", "my_keystore_password", subjectName, keyLength, validityDays);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('my_keystore', 'my_keystore_password') failed.");
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create("my_keystore", "my_keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ longBowTestCase_SetClipBoardData(testCase, factory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ CCNxPortalFactory *factory = longBowTestCase_GetClipBoardData(testCase);
+ ccnxPortalFactory_Release(&factory);
+
+ parcSecurity_Fini();
+
+ if (parcMemory_Outstanding() != InitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("('%s' leaks memory by %zd\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - InitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalAPI_CreateRelease)
+{
+ CCNxPortalFactory *factory = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalAPI_LoopBack);
+ assertNotNull(portal, "Expected a portal");
+
+ ccnxPortal_Release(&portal);
+ assertNull(portal, "Expected a null portal");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalAPI_SendReceive)
+{
+ CCNxPortalFactory *factory = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalAPI_LoopBack);
+
+ // Send Hello
+ CCNxName *name1 = ccnxName_CreateFromCString("lci:/Hello/World");
+ CCNxInterest *sentInterest1 = ccnxInterest_CreateSimple(name1);
+ ccnxName_Release(&name1);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(sentInterest1);
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+
+ // Send Goodbye. We want to make sure these arrive in that order.
+ CCNxName *name2 = ccnxName_CreateFromCString("lci:/Goodbye/World");
+ CCNxInterest *sentInterest2 = ccnxInterest_CreateSimple(name2);
+ ccnxName_Release(&name2);
+
+ message = ccnxMetaMessage_CreateFromInterest(sentInterest2);
+ ccnxPortal_Send(portal, message, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+
+ // Now verify that they arrive in Hello, Goodbye order.
+
+ CCNxMetaMessage *receivedMessage = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+
+ CCNxInterest *receivedInterest1 = ccnxMetaMessage_GetInterest(receivedMessage);
+ assertTrue(ccnxInterest_Equals(sentInterest1, receivedInterest1), "Expected the Hello interest");
+ ccnxMetaMessage_Release(&receivedMessage);
+ ccnxInterest_Release(&sentInterest1);
+
+ receivedMessage = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ CCNxInterest *receivedInterest2 = ccnxMetaMessage_GetInterest(receivedMessage);
+ assertTrue(ccnxInterest_Equals(sentInterest2, receivedInterest2), "Expected the Goodbye interest");
+ ccnxMetaMessage_Release(&receivedMessage);
+ ccnxInterest_Release(&sentInterest2);
+
+ ccnxPortal_Release(&portal);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalAPI_GetFileId)
+{
+ CCNxPortalFactory *factory = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortal *portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalAPI_LoopBack);
+
+ int fileId = ccnxPortal_GetFileId(portal);
+
+ assertTrue(fileId != -1, "Expected file-id to not be -1");
+
+ ccnxPortal_Release(&portal);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_ccnx_PortalAPI);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAnchor.c b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAnchor.c
new file mode 100644
index 00000000..b2acbf51
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalAnchor.c
@@ -0,0 +1,286 @@
+/*
+ * 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_PortalAnchor.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(ccnx_PortalAnchor)
+{
+ // 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(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Object);
+ LONGBOW_RUN_TEST_FIXTURE(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_PortalAnchor)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_PortalAnchor)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+ assertNotNull(instance, "Expected non-null result from ccnxPortalAnchor_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(ccnxPortalAnchor_Acquire, instance);
+
+ ccnxPortalAnchor_Release(&instance);
+ ccnxName_Release(&name);
+ assertNull(instance, "Expected null result from ccnxPortalAnchor_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_Display);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_ToString);
+ LONGBOW_RUN_TEST_CASE(Object, ccnxPortalAnchor_SerializeDeserialize);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_Copy)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+
+ CCNxPortalAnchor *copy = ccnxPortalAnchor_Copy(instance);
+ assertTrue(ccnxPortalAnchor_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ ccnxPortalAnchor_Release(&instance);
+ ccnxPortalAnchor_Release(&copy);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_Display)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+ ccnxPortalAnchor_Display(instance, 0);
+ ccnxPortalAnchor_Release(&instance);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_Equals)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *x = ccnxPortalAnchor_Create(name, expireTime);
+ CCNxPortalAnchor *y = ccnxPortalAnchor_Create(name, expireTime);
+ CCNxPortalAnchor *z = ccnxPortalAnchor_Create(name, expireTime);
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ ccnxPortalAnchor_Release(&x);
+ ccnxPortalAnchor_Release(&y);
+ ccnxPortalAnchor_Release(&z);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_HashCode)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *x = ccnxPortalAnchor_Create(name, expireTime);
+ CCNxPortalAnchor *y = ccnxPortalAnchor_Create(name, expireTime);
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ ccnxPortalAnchor_Release(&x);
+ ccnxPortalAnchor_Release(&y);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_IsValid)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+ assertTrue(ccnxPortalAnchor_IsValid(instance), "Expected ccnxPortalAnchor_Create to result in a valid instance.");
+
+ ccnxPortalAnchor_Release(&instance);
+ ccnxName_Release(&name);
+
+ assertFalse(ccnxPortalAnchor_IsValid(instance), "Expected ccnxPortalAnchor_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_ToJSON)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+
+ PARCJSON *json = ccnxPortalAnchor_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ ccnxPortalAnchor_Release(&instance);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_ToString)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+
+ char *string = ccnxPortalAnchor_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from ccnxPortalAnchor_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ ccnxPortalAnchor_Release(&instance);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Object, ccnxPortalAnchor_SerializeDeserialize)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *instance = ccnxPortalAnchor_Create(name, expireTime);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ ccnxPortalAnchor_Serialize(instance, composer);
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ CCNxPortalAnchor *copy = ccnxPortalAnchor_Deserialize(buffer);
+
+ assertTrue(ccnxPortalAnchor_Equals(instance, copy), "Expected deserialized form to be equal to the original");
+ ccnxPortalAnchor_Release(&copy);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+ ccnxPortalAnchor_Release(&instance);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, ccnxPortalAnchor_GetNamePrefix);
+
+ LONGBOW_RUN_TEST_CASE(Specialization, ccnxPortalAnchor_GetExpireTime);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialization, ccnxPortalAnchor_GetNamePrefix)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *anchor = ccnxPortalAnchor_Create(name, expireTime);
+
+ CCNxName *actual = ccnxPortalAnchor_GetNamePrefix(anchor);
+
+ assertTrue(ccnxName_Equals(name, actual), "Expected name to be equal.");
+ ccnxPortalAnchor_Release(&anchor);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Specialization, ccnxPortalAnchor_GetExpireTime)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/name");
+ time_t expireTime = 123;
+ CCNxPortalAnchor *anchor = ccnxPortalAnchor_Create(name, expireTime);
+
+ time_t actual = ccnxPortalAnchor_GetExpireTime(anchor);
+
+ assertTrue(expireTime == actual, "Expected expire-time to be equal.");
+ ccnxPortalAnchor_Release(&anchor);
+ ccnxName_Release(&name);
+}
+
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_PortalAnchor);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalFactory.c b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalFactory.c
new file mode 100644
index 00000000..8c98705f
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalFactory.c
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+
+/**
+ * @header <#Headline Name#>
+ * @abstract <#Abstract#>
+ * @discussion
+ * <#Discussion#>
+ *
+ */
+#include "../ccnx_PortalFactory.c"
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_IdentityFile.h>
+
+#include <ccnx/transport/test_tools/bent_pipe.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+
+LONGBOW_TEST_RUNNER(test_ccnx_PortalFactory /*, .requires="FeatureLongBowSubProcess"*/)
+{
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(test_ccnx_PortalFactory)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(test_ccnx_PortalFactory)
+{
+// LongBowSubProcess *metis = longBowTestRunner_GetClipBoardData(testRunner);
+// longBowSubProcess_Display(0, metis);
+// longBowSubProcess_Destroy(&metis);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, ccnxPortalFactory_Create);
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, ccnxPortalFactory_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ unlink("ccnxPortalFactory_keystore");
+
+ 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(CreateAcquireRelease, ccnxPortalFactory_Create)
+{
+ const char *keystoreName = "ccnxPortalFactory_keystore";
+
+ parcSecurity_Init();
+
+ bool success = parcPkcs12KeyStore_CreateFile(keystoreName, "keystore_password", "consumer", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('%s', 'keystore_password') failed.", keystoreName);
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, "keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ ccnxPortalFactory_Release(&factory);
+
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, ccnxPortalFactory_AcquireRelease)
+{
+ const char *keystoreName = "ccnxPortalFactory_keystore";
+
+ parcSecurity_Init();
+
+ bool success = parcPkcs12KeyStore_CreateFile(keystoreName, "keystore_password", "consumer", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('%s', 'keystore_password') failed.", keystoreName);
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, "keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ CCNxPortalFactory *reference = ccnxPortalFactory_Acquire(factory);
+ assertTrue(factory == reference, "Expected Acquire to return its argument.");
+
+ ccnxPortalFactory_Release(&factory);
+ ccnxPortalFactory_Release(&reference);
+
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalFactory_GetIdentity);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalFactory_GetKeyId);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ unlink("ccnxPortalFactory_keystore");
+
+ 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, ccnxPortalFactory_GetIdentity)
+{
+ const char *keystoreName = "ccnxPortalFactory_keystore";
+
+ parcSecurity_Init();
+ bool success = parcPkcs12KeyStore_CreateFile(keystoreName, "keystore_password", "consumer", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('%s', 'keystore_password') failed.", keystoreName);
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, "keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+
+ const PARCIdentity *actual = ccnxPortalFactory_GetIdentity(factory);
+
+ assertTrue(identity == actual, "Expected the result to be the same as provided to the constructor");
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ ccnxPortalFactory_Release(&factory);
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalFactory_GetKeyId)
+{
+ const char *keystoreName = "ccnxPortalFactory_keystore";
+
+ parcSecurity_Init();
+ bool success = parcPkcs12KeyStore_CreateFile(keystoreName, "keystore_password", "consumer", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('%s', 'keystore_password') failed.", keystoreName);
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, "keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+
+ const PARCKeyId *actual = ccnxPortalFactory_GetKeyId(factory);
+
+ PARCSigner *signer = parcIdentity_CreateSigner(identity);
+ PARCKeyId *expected = parcSigner_CreateKeyId(signer);
+ parcSigner_Release(&signer);
+
+ assertTrue(parcKeyId_Equals(expected, actual), "KeyIds not equal");
+
+ parcKeyId_Release(&expected);
+
+ ccnxPortalFactory_Release(&factory);
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, ccnxPortalFactory_Create_NULL_Identity);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ unlink("ccnxPortalFactory_keystore");
+
+ 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(Errors, ccnxPortalFactory_Create_NULL_Identity, .event = &LongBowTrapInvalidValue)
+{
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(NULL);
+
+ ccnxPortalFactory_Release(&factory);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_ccnx_PortalFactory);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalRTA.c b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalRTA.c
new file mode 100755
index 00000000..901b1b7e
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalRTA.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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Runner.
+#include "../ccnx_PortalRTA.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(ccnx_PortalRTA)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified here, but every test must be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ 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_PortalRTA)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_PortalRTA)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalRTA_Chunked);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalRTA_LoopBack);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalRTA_Message);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalRTA_Chunked)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalRTA_LoopBack)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalRTA_Message)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _autowrap_destroy__CCNxPortalRTAContext);
+ LONGBOW_RUN_TEST_CASE(Static, _blockingPortal);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalProtocol_RTALoopback);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalProtocol_RTAMetis);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTAContext_Create);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTAContext_Destroy);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTAContext_Release);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_CreatePortal);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_GetAttributes);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_GetFileId);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_Ignore);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_IsConnected);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_Listen);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_Receive);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_Send);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_SetAttributes);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_Start);
+ LONGBOW_RUN_TEST_CASE(Static, _ccnxPortalRTA_Stop);
+ LONGBOW_RUN_TEST_CASE(Static, _createTransportConfig);
+ LONGBOW_RUN_TEST_CASE(Static, _nonBlockingPortal);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, _autowrap_destroy__CCNxPortalRTAContext)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _blockingPortal)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalProtocol_RTALoopback)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalProtocol_RTAMetis)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTAContext_Create)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTAContext_Destroy)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTAContext_Release)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_CreatePortal)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_GetAttributes)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_GetFileId)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_Ignore)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_IsConnected)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_Listen)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_Receive)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_Send)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_SetAttributes)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_Start)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _ccnxPortalRTA_Stop)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _createTransportConfig)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _nonBlockingPortal)
+{
+ testUnimplemented("");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_PortalRTA);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalStack.c b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalStack.c
new file mode 100755
index 00000000..ebba0dea
--- /dev/null
+++ b/libccnx-portal/ccnx/api/ccnx_Portal/test/test_ccnx_PortalStack.c
@@ -0,0 +1,366 @@
+/*
+ * 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_PortalStack.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <ccnx/api/ccnx_Portal/ccnx_PortalFactory.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_IdentityFile.h>
+
+LONGBOW_TEST_RUNNER(test_ccnx_PortalStack)
+{
+ // 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(CreateRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_ccnx_PortalStack)
+{
+ 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(test_ccnx_PortalStack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_FIXTURE(CreateRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateRelease, CreateRelease);
+}
+
+static uint32_t setupFixtureAllocations;
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateRelease)
+{
+ setupFixtureAllocations = parcMemory_Outstanding();
+ parcSecurity_Init();
+
+ const char *keystoreName = "test_ccnx_PortalImplementation_keystore";
+
+ bool success = parcPkcs12KeyStore_CreateFile(keystoreName, "keystore_password", "consumer", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('%s', 'keystore_password') failed.", keystoreName);
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, "keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ longBowTestCase_SetClipBoardData(testCase, factory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateRelease)
+{
+ CCNxPortalFactory *factory = (CCNxPortalFactory *) longBowTestCase_GetClipBoardData(testCase);
+
+ ccnxPortalFactory_Release(&factory);
+
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(setupFixtureAllocations, "%s", longBowTestCase_GetName(testCase))) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void
+_mockStart(void *privateData)
+{
+}
+
+static void
+_mockStop(void *privateData)
+{
+}
+
+static CCNxMetaMessage *
+_mockRead(void *privateData, const uint64_t *microSeconds)
+{
+ CCNxName *name = ccnxName_Create();
+ PARCBuffer *payload = parcBuffer_Allocate(10);
+ CCNxContentObject *object = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ ccnxName_Release(&name);
+
+ parcBuffer_Release(&payload);
+
+ CCNxMetaMessage *result = ccnxMetaMessage_CreateFromContentObject(object);
+ ccnxContentObject_Release(&object);
+ return result;
+}
+
+static bool
+_mockSend(void *privateData, const CCNxMetaMessage *message, const uint64_t *microSeconds)
+{
+ return true;
+}
+
+static bool
+_mockListen(void *privateData, const CCNxName *name, const uint64_t *microSeconds)
+{
+ return true;
+}
+
+static bool
+_mockIgnore(void *privateData, const CCNxName *name, const uint64_t *microSeconds)
+{
+ return true;
+}
+
+static int
+_mockGetFileId(void *privateData)
+{
+ return 2;
+}
+
+static CCNxPortalAttributes *
+_mockGetAttributes(void *privateData)
+{
+ return NULL;
+}
+
+static bool
+_mockSetAttributes(void *privateData, const CCNxPortalAttributes *attributes)
+{
+ return true;
+}
+
+LONGBOW_TEST_CASE(CreateRelease, CreateRelease)
+{
+ CCNxPortalFactory *factory = (CCNxPortalFactory *) longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxPortalAttributes *attributes = NULL;
+ CCNxPortalStack *actual =
+ ccnxPortalStack_Create(factory,
+ attributes,
+ _mockStart,
+ _mockStop,
+ _mockRead,
+ _mockSend,
+ _mockListen,
+ _mockIgnore,
+ _mockGetFileId,
+ _mockSetAttributes,
+ _mockGetAttributes,
+ parcMemory_Allocate(10),
+ parcMemory_DeallocateImpl);
+
+ parcObjectTesting_AssertAcquire(actual);
+
+ ccnxPortalStack_Release(&actual);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_GetFileId);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_GetKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_GetAttributes);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_SetAttributes);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_Listen);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_Ignore);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_Send);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_Receive);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_Start);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_Stop);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxPortalStack_GetError);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ setupFixtureAllocations = parcMemory_Outstanding();
+ parcSecurity_Init();
+
+ const char *keystoreName = "test_ccnx_PortalImplementation_keystore";
+
+ bool success = parcPkcs12KeyStore_CreateFile(keystoreName, "keystore_password", "consumer", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile('%s', 'keystore_password') failed.", keystoreName);
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, "keystore_password");
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+
+ CCNxPortalFactory *factory = ccnxPortalFactory_Create(identity);
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+
+ const CCNxPortalAttributes *attributes = &ccnxPortalAttributes_NonBlocking;
+
+ CCNxPortalStack *stack = ccnxPortalStack_Create(factory,
+ attributes,
+ _mockStart,
+ _mockStop,
+ _mockRead,
+ _mockSend,
+ _mockListen,
+ _mockIgnore,
+ _mockGetFileId,
+ _mockSetAttributes,
+ _mockGetAttributes,
+ parcMemory_Allocate(10),
+ parcMemory_DeallocateImpl);
+ ccnxPortalFactory_Release(&factory);
+ longBowTestCase_SetClipBoardData(testCase, stack);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ ccnxPortalStack_Release(&stack);
+
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(setupFixtureAllocations, "%s", longBowTestCase_GetName(testCase))) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_GetError)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+ extern int errno;
+ errno = 0;
+ int actual = ccnxPortalStack_GetErrorCode(stack);
+ assertTrue(actual == 0, "Expected ccnxPortalStack_GetErrorCode to return 0, actual %d", actual);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_Start)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ bool actual = ccnxPortalStack_Start(stack);
+ assertTrue(actual, "Expected ccnxPortalStack_Start to return true");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_Stop)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+ bool actual = ccnxPortalStack_Stop(stack);
+
+ assertTrue(actual, "Expected ccnxPortalStack_Stop to return true");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_Receive)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxMetaMessage *result = ccnxPortalStack_Receive(stack, CCNxStackTimeout_Never);
+ assertTrue(result, "Expected ccnxPortalStack_Listen to return true.");
+ ccnxMetaMessage_Release(&result);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_Send)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxName *name = ccnxName_Create();
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+ ccnxInterest_Release(&interest);
+
+ bool result = ccnxPortalStack_Send(stack, message, CCNxStackTimeout_Never);
+ ccnxMetaMessage_Release(&message);
+ assertTrue(result, "Expected ccnxPortalStack_Ignore to return true.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_Listen)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxName *name = ccnxName_Create();
+ bool result = ccnxPortalStack_Listen(stack, name, CCNxStackTimeout_Never);
+ ccnxName_Release(&name);
+ assertTrue(result, "Expected ccnxPortalStack_Listen to return true.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_Ignore)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxName *name = ccnxName_Create();
+ bool result = ccnxPortalStack_Ignore(stack, name, CCNxStackTimeout_Never);
+ ccnxName_Release(&name);
+ assertTrue(result, "Expected ccnxPortalStack_Ignore to return true.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_SetAttributes)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ const CCNxPortalAttributes *attributes = &ccnxPortalAttributes_NonBlocking;
+ bool result = ccnxPortalStack_SetAttributes(stack, attributes);
+ assertTrue(result, "Expected ccnxPortalStack_SetAttributes to return true.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_GetAttributes)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ ccnxPortalStack_GetAttributes(stack);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_GetFileId)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ int fileId = ccnxPortalStack_GetFileId(stack);
+ assertFalse(fileId == -1, "Expected ccnxPortalStack_GetFileId to not return -1.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxPortalStack_GetKeyId)
+{
+ CCNxPortalStack *stack = (CCNxPortalStack *) longBowTestCase_GetClipBoardData(testCase);
+
+ const PARCKeyId *keyId = ccnxPortalStack_GetKeyId(stack);
+ assertNotNull(keyId, "Expected non-NULL result from ccnxPortalStack_GetKeyId");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_ccnx_PortalStack);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-portal/cmake/Modules/FindCCNX_Common.cmake b/libccnx-portal/cmake/Modules/FindCCNX_Common.cmake
new file mode 100644
index 00000000..2629c160
--- /dev/null
+++ b/libccnx-portal/cmake/Modules/FindCCNX_Common.cmake
@@ -0,0 +1,39 @@
+########################################
+#
+# Find the Libparc libraries and includes
+# This module sets:
+# CCNX_COMMON_FOUND: True if Libparc was found
+# CCNX_COMMON_LIBRARY: The Libparc library
+# CCNX_COMMON_LIBRARIES: The Libparc library and dependencies
+# CCNX_COMMON_INCLUDE_DIR: The Libparc include dir
+#
+
+set(CCNX_COMMON_SEARCH_PATH_LIST
+ ${CCNX_COMMON_HOME}
+ $ENV{CCNX_COMMON_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(CCNX_COMMON_INCLUDE_DIR ccnx/common/libccnxCommon_About.h
+ HINTS ${CCNX_COMMON_SEARCH_PATH_LIST}
+ PATH_SUFFIXES include
+ DOC "Find the Libccnx-common includes" )
+
+find_library(CCNX_COMMON_LIBRARY NAMES ccnx_common
+ HINTS ${CCNX_COMMON_SEARCH_PATH_LIST}
+ PATH_SUFFIXES lib
+ DOC "Find the Libccnx-common libraries" )
+
+set(CCNX_COMMON_LIBRARIES ${CCNX_COMMON_LIBRARY})
+set(CCNX_COMMON_INCLUDE_DIRS ${CCNX_COMMON_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CCNX_Common DEFAULT_MSG CCNX_COMMON_LIBRARY CCNX_COMMON_INCLUDE_DIR)
diff --git a/libccnx-portal/cmake/Modules/FindCCNX_Transport_Rta.cmake b/libccnx-portal/cmake/Modules/FindCCNX_Transport_Rta.cmake
new file mode 100644
index 00000000..c43436d1
--- /dev/null
+++ b/libccnx-portal/cmake/Modules/FindCCNX_Transport_Rta.cmake
@@ -0,0 +1,50 @@
+########################################
+#
+# Find the Libccnx-transport libraries and includes
+# This module sets:
+# CCNX_TRANSPORT_RTA_FOUND: True if Libparc was found
+# CCNX_TRANSPORT_RTA_LIBRARY: The Libparc library
+# CCNX_TRANSPORT_RTA_LIBRARIES: The Libparc library and dependencies
+# CCNX_TRANSPORT_RTA_INCLUDE_DIR: The Libparc include dir
+#
+
+set(CCNX_TRANSPORT_RTA_SEARCH_PATH_LIST
+ ${CCNX_TRANSPORT_RTA_HOME}
+ $ENV{CCNX_TRANSPORT_RTA_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(CCNX_TRANSPORT_RTA_INCLUDE_DIR ccnx/transport/librta_About.h
+ HINTS ${CCNX_TRANSPORT_RTA_SEARCH_PATH_LIST}
+ PATH_SUFFIXES include
+ DOC "Find the Libccnx-transport-rta includes" )
+
+find_library(CCNX_TRANSPORT_RTA_LIBRARY NAMES ccnx_transport_rta
+ HINTS ${CCNX_TRANSPORT_RTA_SEARCH_PATH_LIST}
+ PATH_SUFFIXES lib
+ DOC "Find the Libccnx-transport-rta libraries" )
+
+find_library(CCNX_API_NOTIFY_LIBRARY NAMES ccnx_api_notify
+ HINTS ${CCNX_TRANSPORT_RTA_SEARCH_PATH_LIST}
+ PATH_SUFFIXES lib
+ DOC "Find the Libccnx-transport-rta libraries" )
+
+find_library(CCNX_API_CONTROL_LIBRARY NAMES ccnx_api_control
+ HINTS ${CCNX_TRANSPORT_RTA_SEARCH_PATH_LIST}
+ PATH_SUFFIXES lib
+ DOC "Find the Libccnx-transport-rta libraries" )
+
+set(CCNX_TRANSPORT_RTA_LIBRARIES ${CCNX_TRANSPORT_RTA_LIBRARY} ${CCNX_API_CONTROL_LIBRARY} ${CCNX_API_NOTIFY_LIBRARY})
+
+set(CCNX_TRANSPORT_RTA_INCLUDE_DIRS ${CCNX_TRANSPORT_RTA_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CCNX_Transport_Api DEFAULT_MSG CCNX_TRANSPORT_RTA_LIBRARY CCNX_TRANSPORT_RTA_INCLUDE_DIR)
diff --git a/libccnx-portal/cmake/Modules/FindLibEvent.cmake b/libccnx-portal/cmake/Modules/FindLibEvent.cmake
new file mode 100644
index 00000000..2d1ca4fe
--- /dev/null
+++ b/libccnx-portal/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-portal/cmake/Modules/FindLibparc.cmake b/libccnx-portal/cmake/Modules/FindLibparc.cmake
new file mode 100644
index 00000000..02835161
--- /dev/null
+++ b/libccnx-portal/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-portal/cmake/Modules/FindLongBow.cmake b/libccnx-portal/cmake/Modules/FindLongBow.cmake
new file mode 100644
index 00000000..e35888eb
--- /dev/null
+++ b/libccnx-portal/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-portal/cmake/Modules/FindUncrustify.cmake b/libccnx-portal/cmake/Modules/FindUncrustify.cmake
new file mode 100644
index 00000000..e53f65fe
--- /dev/null
+++ b/libccnx-portal/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-portal/cmake/Modules/detectCacheSize.cmake b/libccnx-portal/cmake/Modules/detectCacheSize.cmake
new file mode 100644
index 00000000..469d2627
--- /dev/null
+++ b/libccnx-portal/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-portal/cmake/Modules/version.cmake b/libccnx-portal/cmake/Modules/version.cmake
new file mode 100644
index 00000000..74831674
--- /dev/null
+++ b/libccnx-portal/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-portal/cmake/get_version.sh b/libccnx-portal/cmake/get_version.sh
new file mode 100755
index 00000000..34c6ddb2
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/.gitignore b/libccnx-portal/documentation/.gitignore
new file mode 100644
index 00000000..bb5d033a
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/CMakeLists.txt b/libccnx-portal/documentation/CMakeLists.txt
new file mode 100644
index 00000000..13a839ad
--- /dev/null
+++ b/libccnx-portal/documentation/CMakeLists.txt
@@ -0,0 +1,20 @@
+find_package(Doxygen)
+
+if(DOXYGEN_FOUND)
+ configure_file(libccnx_api_portal-stage1.doxygen.in libccnx_api_portal-stage1.doxygen @ONLY)
+ configure_file(libccnx_api_portal-stage2.doxygen.in libccnx_api_portal-stage2.doxygen @ONLY)
+ add_custom_target(docs
+ DEPENDS doctags documentation)
+ add_custom_target(doctags
+ ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/libccnx_api_portal-stage1.doxygen
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating Doctags" VERBATIM )
+ add_custom_target(documentation
+ ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/libccnx_api_portal-stage2.doxygen
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating Documentation" VERBATIM )
+ add_custom_target(clobber-docs
+ COMMAND /bin/rm -rf ${CMAKE_CURRENT_BINARY_DIR}/libccnx_api_portal-documentation
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Removing Documentation" VERBATIM )
+endif(DOXYGEN_FOUND)
diff --git a/libccnx-portal/documentation/DoxygenLayout.xml b/libccnx-portal/documentation/DoxygenLayout.xml
new file mode 100644
index 00000000..759a9cd4
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css b/libccnx-portal/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css
new file mode 100644
index 00000000..c4cadf15
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css.map b/libccnx-portal/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css.map
new file mode 100644
index 00000000..016a8dab
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.min.css b/libccnx-portal/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.min.css
new file mode 100644
index 00000000..4c3e7bad
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/bootstrap/css/bootstrap.css b/libccnx-portal/documentation/doxygen-extras/bootstrap/css/bootstrap.css
new file mode 100644
index 00000000..c6f3d210
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/bootstrap/css/bootstrap.css.map b/libccnx-portal/documentation/doxygen-extras/bootstrap/css/bootstrap.css.map
new file mode 100644
index 00000000..a02f6ba0
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/bootstrap/css/bootstrap.min.css b/libccnx-portal/documentation/doxygen-extras/bootstrap/css/bootstrap.min.css
new file mode 100644
index 00000000..b6fe4e0f
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eot b/libccnx-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 00000000..4a4ca865
--- /dev/null
+++ b/libccnx-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eot
Binary files differ
diff --git a/libccnx-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.svg b/libccnx-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 00000000..25691af8
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttf b/libccnx-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 00000000..67fa00bf
--- /dev/null
+++ b/libccnx-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttf
Binary files differ
diff --git a/libccnx-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woff b/libccnx-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 00000000..8c54182a
--- /dev/null
+++ b/libccnx-portal/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woff
Binary files differ
diff --git a/libccnx-portal/documentation/doxygen-extras/bootstrap/js/bootstrap.js b/libccnx-portal/documentation/doxygen-extras/bootstrap/js/bootstrap.js
new file mode 100644
index 00000000..b6ac8d99
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/bootstrap/js/bootstrap.min.js b/libccnx-portal/documentation/doxygen-extras/bootstrap/js/bootstrap.min.js
new file mode 100644
index 00000000..d8398659
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/bootstrap/js/npm.js b/libccnx-portal/documentation/doxygen-extras/bootstrap/js/npm.js
new file mode 100644
index 00000000..bf6aa806
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/customdoxygen.css b/libccnx-portal/documentation/doxygen-extras/customdoxygen.css
new file mode 100644
index 00000000..8560f848
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/doxy-boot.js b/libccnx-portal/documentation/doxygen-extras/doxy-boot.js
new file mode 100644
index 00000000..5ee5fa37
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/doxygen-bootstrap.js b/libccnx-portal/documentation/doxygen-extras/doxygen-bootstrap.js
new file mode 100755
index 00000000..2ddb6474
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/doxygen-extras/footer.html b/libccnx-portal/documentation/doxygen-extras/footer.html
new file mode 100755
index 00000000..c3bc8198
--- /dev/null
+++ b/libccnx-portal/documentation/doxygen-extras/footer.html
@@ -0,0 +1,11 @@
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+</div>
+<!--END GENERATE_TREEVIEW-->
+</div>
+</div>
+</div>
+</div>
+</div>
+<hr class="footer"/>
+</body>
+</html>
diff --git a/libccnx-portal/documentation/doxygen-extras/header.html b/libccnx-portal/documentation/doxygen-extras/header.html
new file mode 100755
index 00000000..afc898c2
--- /dev/null
+++ b/libccnx-portal/documentation/doxygen-extras/header.html
@@ -0,0 +1,42 @@
+<!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>
+ <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-portal/documentation/doxygen-extras/masthead.css b/libccnx-portal/documentation/doxygen-extras/masthead.css
new file mode 100644
index 00000000..7827e079
--- /dev/null
+++ b/libccnx-portal/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-portal/documentation/images/noise_gradient.jpg b/libccnx-portal/documentation/images/noise_gradient.jpg
new file mode 100644
index 00000000..30ecc02c
--- /dev/null
+++ b/libccnx-portal/documentation/images/noise_gradient.jpg
Binary files differ
diff --git a/libccnx-portal/documentation/libccnx_api_portal-stage1.doxygen.in b/libccnx-portal/documentation/libccnx_api_portal-stage1.doxygen.in
new file mode 100644
index 00000000..ec6bf37a
--- /dev/null
+++ b/libccnx-portal/documentation/libccnx_api_portal-stage1.doxygen.in
@@ -0,0 +1,2428 @@
+# 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 = @CMAKE_CURRENT_SOURCE_DIR@/doxygen-extras/header.html
+
+# footer. See HTML_HEADER for more information on how to generate a default
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# to 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 = @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 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-portal/documentation/libccnx_api_portal-stage2.doxygen.in b/libccnx-portal/documentation/libccnx_api_portal-stage2.doxygen.in
new file mode 100644
index 00000000..988a735b
--- /dev/null
+++ b/libccnx-portal/documentation/libccnx_api_portal-stage2.doxygen.in
@@ -0,0 +1,2406 @@
+# 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 = @CMAKE_CURRENT_SOURCE_DIR@/../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 = @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_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 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=@CMAKE_CURRENT_SOURCE_DIR@/../libccnx_api_notify-documentation/html \
+ libccnx.doctags=@CMAKE_CURRENT_SOURCE_DIR@/../libccnx-documentation/html \
+ libccnx_api_control.doctags=@CMAKE_CURRENT_SOURCE_DIR@/../libccnx_api_control-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 = 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-portal/documentation/stylesheet.css b/libccnx-portal/documentation/stylesheet.css
new file mode 100644
index 00000000..fb5cda7c
--- /dev/null
+++ b/libccnx-portal/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;
+}
diff --git a/libccnx-transport-rta/.gitignore b/libccnx-transport-rta/.gitignore
new file mode 100644
index 00000000..c9e4a9a0
--- /dev/null
+++ b/libccnx-transport-rta/.gitignore
@@ -0,0 +1,98 @@
+VERSION
+.cproject
+.project
+*.plist
+libccnx*.tar.gz
+
+LongBow
+include
+lib
+.DS_Store
+*.o
+*.lo
+build/
+conf.mk
+*.dSYM
+*.gcda
+*.gcno
+*.gcov
+*.a
+*.la
+*.swp
+.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-transport-rta/AUTHORS b/libccnx-transport-rta/AUTHORS
new file mode 100644
index 00000000..b6b97f75
--- /dev/null
+++ b/libccnx-transport-rta/AUTHORS
@@ -0,0 +1,9 @@
+Libccnx-transport-rta authors are listed below
+
+ Glenn Scott <Glenn.Scott@parc.com>
+ Marc Mosko <Marc.Mosko@parc.com>
+ Michele Papalini <micpapal@cisco.com>
+
+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-transport-rta/BASE_VERSION b/libccnx-transport-rta/BASE_VERSION
new file mode 100644
index 00000000..d3827e75
--- /dev/null
+++ b/libccnx-transport-rta/BASE_VERSION
@@ -0,0 +1 @@
+1.0
diff --git a/libccnx-transport-rta/CMakeLists.txt b/libccnx-transport-rta/CMakeLists.txt
new file mode 100644
index 00000000..39ce0d11
--- /dev/null
+++ b/libccnx-transport-rta/CMakeLists.txt
@@ -0,0 +1,78 @@
+cmake_minimum_required(VERSION 3.2)
+project(Libccnx-transport)
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
+
+set(CMAKE_C_STANDARD 99)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+
+if( UNIX )
+ link_libraries(m)
+endif( UNIX )
+
+include( CTest )
+include( version )
+include( detectCacheSize )
+
+if(ANDROID_API)
+ message("############ Detected cross compile for $ENV{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 -DCCNxTransport_DISABLE_VALIDATION -DLIBRTA_DISABLE_VALIDATION -DTransportLibrary_DISABLE_VALIDATION")
+endif()
+
+#set(CMAKE_C_FLAGS_NOPANTS "${CMAKE_C_FLAGS_NOPANTS} -O3 -DNDEBUG -DCCNxTransport_DISABLE_VALIDATION -DLIBRTA_DISABLE_VALIDATION -DTransportLibrary_DISABLE_VALIDATION")
+
+include_directories(${PROJECT_SOURCE_DIR}
+ ${PROJECT_SOURCE_DIR}/ccnx/transport/transport_rta ${PROJECT_BINARY_DIR}/ccnx)
+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( CCNX_Common REQUIRED )
+include_directories(${CCNX_COMMON_INCLUDE_DIRS})
+
+find_package ( Threads REQUIRED )
+
+find_package ( OpenSSL REQUIRED )
+
+find_package( Doxygen )
+
+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} ${LIBEVENT_LIBRARIES})
+ target_link_libraries(${ARGV0} ${OPENSSL_LIBRARIES})
+ target_link_libraries(${ARGV0} ${CMAKE_THREAD_LIBS_INIT})
+ target_link_libraries(${ARGV0} ccnx_transport_rta)
+ target_link_libraries(${ARGV0} ccnx_api_control)
+ target_link_libraries(${ARGV0} ccnx_api_notify)
+ target_link_libraries(${ARGV0} ${CCNX_COMMON_LIBRARIES})
+ target_link_libraries(${ARGV0} ${LIBPARC_LIBRARIES})
+ add_test(${ARGV0} ${ARGV0})
+ set_target_properties(${ARGV0} PROPERTIES FOLDER Test)
+ endmacro(AddTest)
+endif()
+
+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_subdirectory(ccnx)
diff --git a/libccnx-transport-rta/LICENSE b/libccnx-transport-rta/LICENSE
new file mode 100644
index 00000000..318b3f59
--- /dev/null
+++ b/libccnx-transport-rta/LICENSE
@@ -0,0 +1,12 @@
+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-transport-rta/README.md b/libccnx-transport-rta/README.md
new file mode 100644
index 00000000..94ec9eb4
--- /dev/null
+++ b/libccnx-transport-rta/README.md
@@ -0,0 +1,87 @@
+Libccnx-transport-rta
+=======
+The CCNx RTA Stack implementation
+
+## Quick Start ##
+```
+$ git clone -b ccnxlibs/master https://gerrit.fd.io/r/cicn ccnxlibs
+$ cd ccnxlibs/libccnx-transport-rta
+$ mkdir build
+$ cd build
+$ cmake ..
+$ make
+$ make test
+$ make install
+```
+
+## Introduction ##
+
+The CCNx Transport RTA stack is a CCNx networking base stack.
+
+## Using Libccnx-transport-rta ##
+
+### Platforms ###
+
+Libccnx-transport-rta 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
+- Libccnx-common
+
+```
+$ git clone -b cframework/master https://gerrit.fd.io/r/cicn cframework;
+$ git clone -b ccnxlibs/master https://gerrit.fd.io/r/cicn ccnxlibs;
+```
+-
+Documentation dependencies:
+
+- Doxygen
+
+### Using Libccnx-transport-rta ###
+
+Libccnx-transport-rta 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-transport-rta library.
+
+```
+CCNX_HOME=<directory-where-Libccnx-transport-rta-is-installed>
+
+-I${CCNX_HOME}/include -L${CCNX_HOME}/lib -lccnx_transport_rta -lccnx_api_notify -lccnx_api_control
+```
+
+### 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-transport-rta/ccnx/CMakeLists.txt b/libccnx-transport-rta/ccnx/CMakeLists.txt
new file mode 100644
index 00000000..997b4f54
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/CMakeLists.txt
@@ -0,0 +1,4 @@
+configure_file(config.h.in config.h @ONLY)
+
+add_subdirectory(api)
+add_subdirectory(transport)
diff --git a/libccnx-transport-rta/ccnx/api/CMakeLists.txt b/libccnx-transport-rta/ccnx/api/CMakeLists.txt
new file mode 100644
index 00000000..971a364e
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(control)
+add_subdirectory(notify)
diff --git a/libccnx-transport-rta/ccnx/api/control/CMakeLists.txt b/libccnx-transport-rta/ccnx/api/control/CMakeLists.txt
new file mode 100644
index 00000000..b0b3e71a
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/CMakeLists.txt
@@ -0,0 +1,91 @@
+# Define a few configuration variables that we want accessible in the software
+
+set(CCNX_API_CONTROL_HEADERS
+ ccnxControlAPI_About.h
+ cpi_Acks.h
+ cpi_Address.h
+ cpi_AddressList.h
+ cpi_CancelFlow.h
+ cpi_Connection.h
+ cpi_ConnectionEthernet.h
+ cpi_ConnectionList.h
+ cpi_ControlMessage.h
+ cpi_ControlFacade.h
+ cpi_Forwarding.h
+ cpi_Interface.h
+ cpi_InterfaceSet.h
+ cpi_InterfaceGeneric.h
+ cpi_InterfaceEthernet.h
+ cpi_InterfaceType.h
+ cpi_InterfaceIPTunnel.h
+ cpi_InterfaceIPTunnelList.h
+ cpi_InterfaceLocal.h
+ cpi_Listener.h
+ cpi_NameRouteType.h
+ cpi_ManageLinks.h
+ cpi_ManageCaches.h
+ cpi_ManageWldr.h
+ cpi_RouteEntry.h
+ cpi_RouteEntryList.h
+ cpi_NameRouteProtocolType.h
+ cpi_ForwardingStrategy.h
+ controlPlaneInterface.h
+)
+
+set(CCNX_API_CONTROL_SOURCE_FILES
+ ccnxControlAPI_About.c
+ cpi_Acks.c
+ cpi_Address.c
+ cpi_AddressList.c
+ cpi_CancelFlow.c
+ cpi_Connection.c
+ cpi_ConnectionEthernet.c
+ cpi_ConnectionList.c
+ cpi_ControlMessage.c
+ cpi_ControlFacade.c
+ cpi_Forwarding.c
+ cpi_Interface.c
+ cpi_InterfaceSet.c
+ cpi_InterfaceGeneric.c
+ cpi_InterfaceEthernet.c
+ cpi_InterfaceIPTunnel.c
+ cpi_InterfaceIPTunnelList.c
+ cpi_InterfaceType.c
+ cpi_Listener.c
+ cpi_NameRouteType.c
+ cpi_ManageLinks.c
+ cpi_ManageCaches.c
+ cpi_ManageWldr.c
+ cpi_NameRouteProtocolType.c
+ cpi_RouteEntry.c
+ cpi_RouteEntryList.c
+ cpi_ForwardingStrategy.c
+ controlPlaneInterface.c
+)
+
+
+add_library(ccnx_api_control STATIC ${CCNX_API_CONTROL_SOURCE_FILES} ${CCNX_API_CONTROL_HEADERS})
+add_library(ccnx_api_control.shared SHARED ${CCNX_API_CONTROL_SOURCE_FILES})
+
+source_group(Sources FILES ${CCNX_API_CONTROL_SOURCE_FILES})
+source_group(Sources FILES ${CCNX_API_CONTROL_HEADERS})
+
+set_target_properties(ccnx_api_control.shared PROPERTIES
+ C_STANDARD 99
+ SOVERSION 1
+ VERSION 1.0
+ OUTPUT_NAME ccnx_api_control )
+
+set(libccnx_api_control_libraries
+ ccnx_api_control
+ ccnx_api_control.shared
+ )
+
+foreach(lib ${libccnx_api_control_libraries})
+ install(TARGETS ${lib} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
+ set_property(TARGET ${lib} PROPERTY C_STANDARD 99)
+endforeach()
+
+install(FILES ${CCNX_API_CONTROL_HEADERS} DESTINATION include/ccnx/api/control )
+
+add_subdirectory(test)
diff --git a/libccnx-transport-rta/ccnx/api/control/README.txt b/libccnx-transport-rta/ccnx/api/control/README.txt
new file mode 100644
index 00000000..291a2088
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/README.txt
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ */
+
+Control Plane Interface (CPI)
+
+Control's the FIB and forwarder interfaces.
+
+Also controls stack behavior, such as flushing the stack.
+
+These messages are meant to be sent up and down transport connections, not
+over the command port.
+
+The matieral below describes the networking model used by the Transport.
+
+=====================================
+
+Most of the API functions are found in cpi_ManageLinks.h and cpi_Forwarding.h. Those
+have the calls to generate CPIControlMessages for dealing with interfaces and dealing with
+forwarding.
+
+=====================================
+0) Overview
+
+To use the ControlPlaneInterface, you create CPIControlMessages, then send them
+down a Transport connection to a forwarder. The Forwarder Connector, in conjunction
+with the forwarder will send a CPIControlMessage back up the stack to you. The
+Response might be an ACK, a NACK, or a Respone with data.
+
+Different Transports and different forwarders will have their own models of
+ports, interfaces, and addresses. It is the job of the Transport and the
+Forwarder Connector to map those different views in to the single consistent
+view exposed here to the API.
+
+All addressable entities have an "Interface Index" (ifidx), similar to
+RFC 3493, Section 4. The interface index used by the Transport includes
+virtual interfaces that may not exist at the kernel level, so the ifidx
+is not equal to a kernel interface index. For some devices, the CCNx
+forwarder might not even be on the same physical entity.
+
+Not all forwarders support all options. See forwarder specific documentation.
+
+=====================================
+1) Interfaces
+
+An interface is a physical port or virtual device on the system.
+It may have zero or more addresses, depending on the type.
+
+- P2P interface (e.g. serial)
+- Ethernet
+- Loopback
+
+Some interfaces depend on other interfaces:
+
+- VLAN
+- L2TP
+- PPP
+- LAG
+
+Interfaces will have a layer 2 (L2) address and may have L3 addresses too.
+
+All physical and virtual interfaces have an interface index.
+
+=====================================
+2) Overlay Interfaces (Tunnels and Multicast groups)
+
+Tunnels are a special type of Interface that have a point-to-point
+connection with a remote peer. Another type of overlay is
+an IP multicast group.
+
+Tunnels have a specific local source address. Each tunnel and multicast
+group overlay has an interface index.
+
+Type types of interaces are:
+- IP/UDP point-to-point tunnel
+- IPv6/UDP point-to-point tunnel
+- IP/TCP point-to-point tunnel
+- IPv6/TCP point-to-point tunnel
+- IP/UDP multicast group
+- IPv6/UDP multicast group
+
+
+=====================================
+3) Addresses
+
+Addresses are used for setting up tunnels and overlays. They
+are also used in the FIB to indicate a next hop.
+
+An Interface address may be used with tunnels and overlays to
+indicate that a message (i.e. interest) should be sent on that
+overlay.
+
+- IPv4 unicast
+- IPv4 multicast
+- IPv6 unicast
+- IPv6 multicast
+- Link unicast
+- Link group
+- Interface
+
+=====================================
+4) Message information
+
+Similar to RFC 3542, Section 6
+
+An outgoing message can specify:
+- The outgoing interface index
+- The outgoing hop limit
+
+If the outgoing interface is specified, it bypasses the normal
+FIB/PIT forwarding rules and forces the message out that interface.
+
+
+Incoming message information may contain:
+- The destination address
+- The arriving interface index
+- The arriving hop limit
+
+There is currently no specification for traffic class.
+
+The destination address will be specific to how the message was
+received. If it was over an IP-based interface, the addresses will
+be IP/IPv6. If it was over a Link interface, the addresses wil be
+media-dependent addresses (e.g. Ethernet MACs).
+
+To control the incoming information, use these functions
+to generate a control message to send down the connection.
+They are similar to an IP(V6)_RECVPKTINFO socket option.
+
+CPIControlMessage * cpi_StartReceivingMessageInfo();
+CPIControlMessage * cpi_StopReceivingMessageInfo();
+
+DESCRIBE HOW IT IS COMMUNICATED IN A CCNxMESSAGE
+
+=====================================
+5) Monitors
+
+A Transport connection can be setup as a Monitor. A Montior is
+an INBOUND ONLY connection for diagnostic purposes. It should
+contain only the minimum necessary components (API, CODEC, Forwarder).
+
+A Monitor has directionality. It may snoop all messages INBOUND or OUTBOUND
+or BOTH on the target. The snooped messages are sent up the monitor
+connection to the API.
+
+A Monitor may be added to an Interface, in which case it will act like
+a promiscuous tap. An INBOUND monitor will see all packets received
+on the interface. An OUTBOUND monitor will see all packets sent on the
+interface.
+
+A Monitor may be added to a namespace. It can be for an exact namespace,
+or it can be a prefix match. It may be INBOUND or OUTBOUND or BOTH.
+
+=====================================
+Common Operations
+
+####
+#### NOTE: This example code is out of date.
+####
+
+----------------------------------------------------------------------------
+a) List the interfaces
+
+CPIControlMessage * cpi_NetworkInterfaceList();
+/* send the control message on a connection */
+
+CPIControlMessage *message = /* receive function */
+if( cpi_IsCpiMessage(message) && cpi_GetMessageType(message) == CPI_RESPONSE &&
+ cpi_GetMessageOperation(message) == CPI_INTERFACE_LIST )
+{
+ unsigned count = cpi_NetworkInterfaceList_Count(message);
+ for(i = 0; i < count; i++)
+ {
+ InterfaceService *entry = cpi_NetworkInterfaceList_Get(message, i);
+ }
+}
+
+ccnxControlMessage_Destroy(&message);
+
+
+----------------------------------------------------------------------------
+b) Create a point-to-point tunnel
+
+CPIAddress * dest = cpiAddress_CreateFromInet((struct sockaddr_in) {
+ .sa_addr = inet_addr("foo.bar.com"),
+ .sa_port = htons(9695)} );
+
+// the address 13.0.1.1. is known to be on the forwarder.
+// You'd learn about it from cpi_NetworkInterfaceList()
+CPIAddress * source = cpiAddress_CreateFromInet((struct sockaddr_in) {
+ .sa_family = AF_INET,
+ .sa_addr = inet_addr("13.0.1.1") } );
+
+CPIControlMessage *udp_tunnel = cpiTunnel_CreateMessage(dest, source, IPPROTO_UDP)
+/* send message down connection */
+
+CPIControlMessage *response = /* receive message function */
+
+if( cpi_IsCpiMessage(response) && cpi_GetMessageType(response) == CPI_RESPONSE &&
+ cpi_GetMessageOperation(response) == CPI_CREATE_TUNNEL )
+{
+ CPITunnel * tunnel = cpiTunnel_ParseMessage(response);
+
+ unsigned ifidx = cpiTunnel_GetInterfaceIndex(tunnel);
+ // ...
+ cpiTunnel_Destroy(&tunnel);
+}
+
+
+
+----------------------------------------------------------------------------
+c) Create an IP multicast overlay
+
+CPIAddress * dest = cpiAddress_CreateFromInet((struct sockaddr_in) {
+ .sa_family = AF_INET,
+ .sa_addr = inet_addr("224.1.100.3"),
+ .sa_port = htons(9695)} );
+
+// the address 13.0.1.1. is known to be on the forwarder.
+// You'd learn about it from cpi_NetworkInterfaceList()
+CPIAddress * source = cpiAddress_CreateFromInet((struct sockaddr_in) {
+ .sa_family = AF_INET,
+ .sa_addr = inet_addr("13.0.1.1") } );
+
+unsigned ifidx = /* interface to join the group */
+
+CPIControlMessage *udp_multicast = cpiMulticast_CreateMessage(dest, source, ifidx)
+/* send message down connection */
+
+CPIControlMessage *response = /* receive message function */
+
+if( cpi_IsCpiMessage(response) && cpi_GetMessageType(response) == CPI_RESPONSE &&
+ cpi_GetMessageOperation(response) == CPI_CREATE_MULTICAST )
+{
+ CPIMulticast * mcast = cpiMulticast_ParseMessage(response);
+ // ...
+ cpiMulticast_Destroy(&tunnel);
+}
+
+----------------------------------------------------------------------------
+d) Create an Ethernet group interface
+
+
+
+
+----------------------------------------------------------------------------
+d) remove a tunnel
+
+----------------------------------------------------------------------------
+d) Setup a FIB entry to a point-to-point tuennl
+
+----------------------------------------------------------------------------
+e) Setup a FIB entry to a multicast group
+
+----------------------------------------------------------------------------
+f) Setup a FIB entry to a Link unicast address
+
+----------------------------------------------------------------------------
+g) Setup a FIB entry to a Link group address
+
+
+
+
diff --git a/libccnx-transport-rta/ccnx/api/control/ccnxControlAPI_About.c b/libccnx-transport-rta/ccnx/api/control/ccnxControlAPI_About.c
new file mode 100644
index 00000000..51b09086
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/ccnxControlAPI_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T09:29:05Z
+
+#include "ccnxControlAPI_About.h"
+
+const char *ccnxControlAPI_What = "@(#)" "ccnxControlAPI " RELEASE_VERSION " 2017-02-20T14:20:58.851661"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+ccnxControlAPIAbout_Name(void)
+{
+ return "ccnxControlAPI";
+}
+
+const char *
+ccnxControlAPIAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+ccnxControlAPIAbout_About(void)
+{
+ return "ccnxControlAPI "RELEASE_VERSION " 2017-02-20T14:20:58.851661" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxControlAPIAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxControlAPIAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxControlAPIAbout_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-transport-rta/ccnx/api/control/ccnxControlAPI_About.h b/libccnx-transport-rta/ccnx/api/control/ccnxControlAPI_About.h
new file mode 100644
index 00000000..ee04c843
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/ccnxControlAPI_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T09:29:05Z
+
+#ifndef ccnxControlAPI_About_h
+#define ccnxControlAPI_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *ccnxControlAPI_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *ccnxControlAPIAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *ccnxControlAPIAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *ccnxControlAPIAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *ccnxControlAPIAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *ccnxControlAPIAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *ccnxControlAPIAbout_LongNotice(void);
+
+#endif // ccnxControlAPI_About_h
diff --git a/libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.c b/libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.c
new file mode 100644
index 00000000..469acd02
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.c
@@ -0,0 +1,449 @@
+/*
+ * 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.
+ */
+
+/**
+ * @header <#Headline Name#>
+ * <#Abstract#>
+ *
+ * <#Discussion#>
+ *
+ * @author Marc Mosko
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+/**
+ * These comments describe the implementation of the protocol described in the header file.
+ *
+ * A Control Plane Information (CPI) message is a JSON object of this form:
+ * {
+ * "CPI_REQUEST" | "CPI_RESPONSE" :
+ * { "SEQUENCE" : <sequence number>,
+ * <operation> : <contents>
+ * }
+ * ["AUTHENTICATOR" : <TBD proof based on request/response, e.g. a crypto signature>]
+ * }
+ *
+ * {
+ * "CPI_ACK" :
+ * { "SEQUENCE" : <sequence number>,
+ * "RETURN" : "ACK" or "NACK",
+ * "REQUEST" : <original request JSON>
+ * [, "MESSAGE" : <optional message> ]
+ * }
+ * ["AUTHENTICATOR" : <TBD proof based on request/response, e.g. a crypto signature>]
+ * }
+ *
+ *
+ * { "REGISTER" :
+ * { "PREFIX" : <name URI string>,
+ * "INTERFACE" : <integer>,
+ * "FLAGS" : <integer>
+ * [, "LIFETIME" : [seconds, micro_seconds] ]
+ * }
+ * }
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include "controlPlaneInterface.h"
+#include "cpi_private.h"
+#include "cpi_NameRouteProtocolType.h"
+#include "cpi_Acks.h"
+#include <ccnx/api/control/cpi_ConnectionEthernet.h>
+
+static const char *cpiRequest = "CPI_REQUEST";
+static const char *cpiResponse = "CPI_RESPONSE";
+static const char *cpiPause = "CPI_PAUSE";
+static const char *cpiFlush = "CPI_FLUSH";
+
+// This is the unique sequence number used by all messages and its thread locks
+static pthread_mutex_t cpiNextSequenceNumberMutex = PTHREAD_MUTEX_INITIALIZER;
+static uint64_t cpiNextSequenceNumber = 1;
+
+const char *
+cpiRequest_GetJsonTag()
+{
+ return cpiRequest;
+}
+
+const char *
+cpiResponse_GetJsonTag()
+{
+ return cpiResponse;
+}
+
+const char *
+cpiSequence_GetJSONTag()
+{
+ return cpiSeqnum;
+}
+
+uint64_t
+cpi_GetNextSequenceNumber(void)
+{
+ uint64_t seqnum;
+
+ int result = pthread_mutex_lock(&cpiNextSequenceNumberMutex);
+ assertTrue(result == 0, "Got error from pthread_mutex_lock: %d", result);
+
+ seqnum = cpiNextSequenceNumber++;
+
+ result = pthread_mutex_unlock(&cpiNextSequenceNumberMutex);
+ assertTrue(result == 0, "Got error from pthread_mutex_unlock: %d", result);
+
+ return seqnum;
+}
+
+CpiOperation
+cpi_getCPIOperation2(const PARCJSON *json)
+{
+ PARCJSONValue *cpi_value = parcJSON_GetValueByName(json, cpiRequest);
+
+ if (cpi_value == NULL) {
+ cpi_value = parcJSON_GetValueByName(json, cpiResponse);
+ }
+ assertNotNull(cpi_value, "Could not get Request or response");
+
+ PARCJSON *cpi_json = parcJSONValue_GetJSON(cpi_value);
+
+ /*
+ * The JSON is defined as { REQUEST : { SEQUENCE: xxx, <OPERATION>: xxx } }
+ * so we want to get the key of the 2nd item (index 1) of the array of objects
+ * under the request
+ */
+
+ PARCJSONPair *item1Pair = parcJSON_GetPairByIndex(cpi_json, 1);
+ PARCBuffer *name = parcJSONPair_GetName(item1Pair);
+ const char *p = parcBuffer_Overlay(name, 0);
+
+ if (strncasecmp(p, cpiForwarding_AddRouteJsonTag(), strlen(cpiForwarding_AddRouteJsonTag())) == 0) {
+ return CPI_REGISTER_PREFIX;
+ }
+
+ if (strncasecmp(p, cpiForwarding_RemoveRouteJsonTag(), strlen(cpiForwarding_RemoveRouteJsonTag())) == 0) {
+ return CPI_UNREGISTER_PREFIX;
+ }
+
+ if (strncasecmp(p, cpiPause, strlen(cpiPause)) == 0) {
+ return CPI_PAUSE;
+ }
+
+ if (strncasecmp(p, cpiFlush, strlen(cpiFlush)) == 0) {
+ return CPI_FLUSH;
+ }
+
+ if (strncasecmp(p, cpiCancelFlow_CancelFlowJsonTag(), strlen(cpiCancelFlow_CancelFlowJsonTag())) == 0) {
+ return CPI_CANCEL_FLOW;
+ }
+
+ if (strncasecmp(p, cpiLinks_InterfaceListJsonTag(), strlen(cpiLinks_InterfaceListJsonTag())) == 0) {
+ return CPI_INTERFACE_LIST;
+ }
+
+ if (strncasecmp(p, cpiForwarding_RouteListJsonTag(), strlen(cpiForwarding_RouteListJsonTag())) == 0) {
+ return CPI_PREFIX_REGISTRATION_LIST;
+ }
+
+ if (strncasecmp(p, cpiLinks_CreateTunnelJsonTag(), strlen(cpiLinks_CreateTunnelJsonTag())) == 0) {
+ return CPI_CREATE_TUNNEL;
+ }
+
+ if (strncasecmp(p, cpiLinks_RemoveTunnelJsonTag(), strlen(cpiLinks_RemoveTunnelJsonTag())) == 0) {
+ return CPI_REMOVE_TUNNEL;
+ }
+
+ if (strncasecmp(p, cpiLinks_ConnectionListJsonTag(), strlen(cpiLinks_ConnectionListJsonTag())) == 0) {
+ return CPI_CONNECTION_LIST;
+ }
+
+ if (strncasecmp(p, cpiLinks_AddEtherConnectionJasonTag(), strlen(cpiLinks_AddEtherConnectionJasonTag())) == 0) {
+ return (CPI_ADD_ETHER_CONNECTION);
+ }
+
+ if (strncasecmp(p, cpiManageChaces_CacheStoreOnJsonTag(), strlen(cpiManageChaces_CacheStoreOnJsonTag())) == 0) {
+ return CPI_CACHE_STORE_ON;
+ }
+
+ if (strncasecmp(p, cpiManageChaces_CacheStoreOffJsonTag(), strlen(cpiManageChaces_CacheStoreOffJsonTag())) == 0) {
+ return CPI_CACHE_STORE_OFF;
+ }
+
+ if (strncasecmp(p, cpiManageChaces_CacheServeOnJsonTag(), strlen(cpiManageChaces_CacheServeOnJsonTag())) == 0) {
+ return CPI_CACHE_SERVE_ON;
+ }
+
+ if (strncasecmp(p, cpiManageChaces_CacheServeOffJsonTag(), strlen(cpiManageChaces_CacheServeOffJsonTag())) == 0) {
+ return CPI_CACHE_SERVE_OFF;
+ }
+
+ if (strncasecmp(p, cpiManageChaces_CacheClearJsonTag(), strlen(cpiManageChaces_CacheClearJsonTag())) == 0) {
+ return CPI_CACHE_CLEAR;
+ }
+
+ if (strncasecmp(p, cpiForwarding_SetStrategyJsonTag(), strlen(cpiForwarding_SetStrategyJsonTag())) == 0) {
+ return CPI_SET_FORWARDING_STRATEGY;
+ }
+
+ if (strncasecmp(p, cpiLinks_SetWldrJsonTag(), strlen(cpiLinks_SetWldrJsonTag())) == 0) {
+ return CPI_SET_WLDR;
+ }
+
+ if (strncasecmp(p, "AddConnEther", strlen("AddConnEther")) == 0) {
+ return CPI_ADD_CONNECTION_ETHERNET;
+ }
+
+ if (strncasecmp(p, "RemoveConnEther", strlen("RemoveConnEther")) == 0) {
+ return CPI_REMOVE_CONNECTION_ETHERNET;
+ }
+
+ if (strncasecmp(p, "AddListener", strlen("AddListener")) == 0) {
+ return CPI_ADD_LISTENER;
+ }
+
+ if (strncasecmp(p, "RemoveListener", strlen("RemoveListener")) == 0) {
+ return CPI_REMOVE_LISTENER;
+ }
+
+ trapIllegalValue(json, "Could not parse: %s\n", parcJSON_ToString(json));
+}
+
+/**
+ * Return the relevant operation from a REQUEST or a REPSONSE.
+ * Do not call on an ACK
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CpiOperation
+cpi_GetMessageOperation(CCNxControl *control)
+{
+ if (cpiConnectionEthernet_IsAddMessage(control)) {
+ return CPI_ADD_CONNECTION_ETHERNET;
+ }
+
+ if (cpiConnectionEthernet_IsRemoveMessage(control)) {
+ return CPI_REMOVE_CONNECTION_ETHERNET;
+ }
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+
+ CpiOperation result = cpi_getCPIOperation2(json);
+ return result;
+}
+
+CpiMessageType
+controlPlaneInterface_GetCPIMessageType(PARCJSON *json)
+{
+ assertNotNull(json, "Invalid state, got NULL json from control message");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpiResponse);
+ if (value != NULL) {
+ return CPI_RESPONSE;
+ }
+
+ value = parcJSON_GetValueByName(json, cpiRequest);
+ if (value != NULL) {
+ return CPI_REQUEST;
+ }
+
+ value = parcJSON_GetValueByName(json, cpiAck);
+ if (value != NULL) {
+ return CPI_ACK;
+ }
+
+ trapIllegalValue(json, "Expected CpiMessageType, actual %s", parcJSON_ToString(json));
+}
+
+/**
+ * You should verify that it's a CPI message with cpi_IsCpiMessage() before using this.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CpiMessageType
+cpi_GetMessageType(const CCNxControl *control)
+{
+ PARCJSON *json = ccnxControl_GetJson(control);
+ CpiMessageType result = controlPlaneInterface_GetCPIMessageType(json);
+ return result;
+}
+
+/**
+ * Returns the inner operation JSON from the request.
+ *
+ * INPUT: "{ CPI_REQUEST: { SEQUENCE:number key: { operation } }}"
+ * OUTPUT: "{ key : { operation } }"
+ *
+ * Example return: "{ operation }"
+ * @param <#param1#>
+ * @return The inner json, do not destroy it
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSONPair *
+cpi_ParseRequest(PARCJSON *request)
+{
+ PARCJSONValue *value = parcJSON_GetValueByName(request, cpiRequest);
+ assertNotNull(value, "Could not find JSON key %s in %s", cpiRequest, parcJSON_ToString(request));
+ assertTrue(parcJSONValue_IsJSON(value), "cpiRequest is unexpected type");
+
+ PARCJSON *requestJson = parcJSONValue_GetJSON(value);
+ PARCJSONPair *result = parcJSON_GetPairByIndex(requestJson, 1);
+
+ return result;
+}
+
+CCNxControl *
+cpi_ForwarderVersion()
+{
+ return NULL;
+}
+
+uint64_t
+controlPlaneInterface_GetSequenceNumber(const PARCJSON *controlPlaneMessage)
+{
+ assertNotNull(controlPlaneMessage, "Invalid state, got NULL json from control message");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(controlPlaneMessage, cpiRequest);
+ if (value == NULL) {
+ value = parcJSON_GetValueByName(controlPlaneMessage, cpiResponse);
+ }
+ if (value == NULL) {
+ value = parcJSON_GetValueByName(controlPlaneMessage, cpiAck);
+ }
+
+ assertNotNull(value, "Could not get request or response");
+
+ PARCJSON *json = parcJSONValue_GetJSON(value);
+ value = parcJSON_GetValueByName(json, cpiSeqnum);
+ assertNotNull(value, "Could not retrieve key %s from CPI section", cpiSeqnum);
+
+ return parcJSONValue_GetInteger(value);
+}
+
+/**
+ * All CPI messages carry a sequence number.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint64_t
+cpi_GetSequenceNumber(CCNxControl *control)
+{
+ PARCJSON *json = ccnxControl_GetJson(control);
+
+ return controlPlaneInterface_GetSequenceNumber(json);
+}
+
+PARCJSON *
+cpi_CreatePauseInputRequest(void)
+{
+ PARCJSON *operation = parcJSON_Create();
+ PARCJSON *result = cpi_CreateRequest(cpiPause, operation);
+ parcJSON_Release(&operation);
+
+ return result;
+}
+
+PARCJSON *
+cpi_CreateFlushRequest(void)
+{
+ PARCJSON *operation = parcJSON_Create();
+ PARCJSON *result = cpi_CreateRequest(cpiFlush, operation);
+ parcJSON_Release(&operation);
+
+ return result;
+}
+
+/**
+ * Given the inner operation member, wrap it in a Request with a sequence number
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *
+cpi_CreateRequest(const char *key, PARCJSON *operation)
+{
+ PARCJSON *result = parcJSON_Create();
+ PARCJSON *request = parcJSON_Create();
+
+ uint64_t seqnum = cpi_GetNextSequenceNumber();
+
+ parcJSON_AddInteger(request, cpiSeqnum, (int) seqnum);
+ parcJSON_AddObject(request, key, operation);
+ parcJSON_AddObject(result, cpiRequest, request);
+ parcJSON_Release(&request);
+
+ return result;
+}
+
+CCNxControl *
+cpi_CreateResponse(CCNxControl *request, PARCJSON *operation)
+{
+ PARCJSON *requestJson = ccnxControl_GetJson(request);
+
+ // use the same key as the request
+ uint64_t seqnum = controlPlaneInterface_GetSequenceNumber(requestJson);
+
+ PARCJSONValue *value = parcJSON_GetValueByName(requestJson, cpiRequest);
+ assertNotNull(value, "Could not get request or response");
+ assertTrue(parcJSONValue_IsJSON(value), "cpiRequest should be a JSON object");
+
+ PARCJSON *operationJson = parcJSONValue_GetJSON(value);
+ PARCJSONPair *pair = parcJSON_GetPairByIndex(operationJson, 1);
+ const PARCBuffer *opKeyBuf = parcJSONPair_GetName(pair);
+ const char *opKey = parcBuffer_ToString(opKeyBuf);
+
+ PARCJSON *response = parcJSON_Create();
+ parcJSON_AddInteger(response, cpiSeqnum, (int) seqnum);
+ parcJSON_AddObject(response, opKey, operation);
+ parcMemory_Deallocate(&opKey);
+
+ PARCJSON *responseJson = parcJSON_Create();
+ parcJSON_AddObject(responseJson, cpiResponse, response);
+ parcJSON_Release(&response);
+
+ CCNxControl *result = ccnxControl_CreateCPIRequest(responseJson);
+
+ parcJSON_Release(&responseJson);
+
+ return result;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.h b/libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.h
new file mode 100644
index 00000000..01b6e861
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.h
@@ -0,0 +1,456 @@
+/*
+ * 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 controlPlaneInterface.h
+ *
+ * Based loosely on Netlink (RFC 3549)
+ *
+ * Constructs `CCNxControl` for common control plane operations.
+ * These methods do not actually communicate with the transport.
+ * The user must send the message down their protocol stack and await a response.
+ *
+ * CPI messages have a Type: Request, Response, or ACK.
+ * A request may ask for an ACK if successful for commands that would otherwise not
+ * produce a response.
+ * Request that fail always generate a NACK.
+ *
+ * All messages must carry a "sequence number" which must be unique within
+ * the Transport.
+ * Although sequence numbers imply an ordering, they do not imply
+ * causality or precedence.
+ * They only imply a duplicate.
+ *
+ * An ACK is a reponse that carries no data, it just ACKs (or NACKs) a sequence number.
+ * A field in the ACK indicates it is an error (NACK). An ACK carries the original
+ * request and an optional message.
+ *
+ * All messages carry a mandatory sequence number,
+ * which is unique in all messages.
+ * An ACK (or NACK) contains the original message that generated the ACK,
+ * including its sequence number.
+ * These conventions allow one to implement a reliable CPI messaging system, if desired.
+ *
+ * The Control Plane operations are:
+ *
+ * * CPI_INTERFACE_LIST
+ * Return: A response with an array of network interfaces ("interfaceIndex", type, and flags), or a NACK.
+ *
+ * * CPI_REGISTER
+ * Add a FIB entry with the given CCNxName prefix to the specified interfaceIndex.
+ * The value of "-1" means the current interface.
+ * Return: an ACK (or NACK)
+ *
+ * * CPI_UNREGISTER
+ * Remove a FIB entry with the given CCNxName prefix from the specified interfaceIndex.
+ * The value of "-1" means the current interface.
+ * Return: an ACK (or NACK)
+ *
+ * * CPI_FORWARDER_VERSION:
+ * Return: Response (a string) or a NACK.
+ *
+ * * CPI_ADDRESS
+ * Request: by interfaceIndex
+ * Response: the sockaddr_storage list for the interface, or a NACK
+ *
+ * * CPI_PREFIX_REGISTRATION_LIST
+ * Request: by interfaceIndex, value "-1" means the current interface
+ * Response: the list of CCNxNames (with their flags) registered on the interface or a NACK
+ *
+ * * CPI_PAUSE_INPUT
+ * Request: by current connection, causes stack to pause the input (top and bottom)
+ * Response: Forwarder sends ACK up the stack.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+/*
+ * This description needs to be revised based on the recent refactoring.
+ *
+ * The user will be interested in cpi_Forwarding.h and cpi_ManageLinks.h.
+ *
+ * Case 1027: need to specify the memory management, especially for variable sized messages.
+ */
+
+#ifndef libccnx_controlPlaneInterface_h
+#define libccnx_controlPlaneInterface_h
+
+#include <ccnx/transport/common/transport_MetaMessage.h>
+#include <sys/socket.h>
+
+#include <ccnx/api/control/cpi_ControlMessage.h>
+#include <ccnx/api/control/cpi_Forwarding.h>
+#include <ccnx/api/control/cpi_ManageLinks.h>
+#include <ccnx/api/control/cpi_CancelFlow.h>
+#include <ccnx/api/control/cpi_ManageCaches.h>
+#include <ccnx/api/control/cpi_ManageWldr.h>
+
+typedef enum {
+ CPI_REQUEST,
+ CPI_RESPONSE, // a resonse with contents
+ CPI_ACK // a response without contents
+} CpiMessageType;
+
+typedef enum {
+ CPI_ERROR, // a NACK response, carries original message
+ CPI_REGISTER_PREFIX,
+ CPI_UNREGISTER_PREFIX,
+ CPI_FORWARDER_VERSION,
+ CPI_INTERFACE_LIST,
+ CPI_ADDRESS,
+ CPI_PREFIX_REGISTRATION_LIST,
+ CPI_PAUSE,
+ CPI_FLUSH,
+ CPI_CANCEL_FLOW,
+ CPI_CREATE_TUNNEL,
+ CPI_REMOVE_TUNNEL,
+ CPI_CONNECTION_LIST,
+ CPI_ADD_ETHER_CONNECTION,
+ CPI_ADD_CONNECTION_ETHERNET,
+ CPI_REMOVE_CONNECTION_ETHERNET,
+ CPI_ADD_LISTENER,
+ CPI_REMOVE_LISTENER,
+ CPI_CACHE_STORE_ON,
+ CPI_CACHE_STORE_OFF,
+ CPI_CACHE_SERVE_ON,
+ CPI_CACHE_SERVE_OFF,
+ CPI_CACHE_CLEAR,
+ CPI_SET_FORWARDING_STRATEGY,
+ CPI_SET_WLDR
+} CpiOperation;
+
+typedef enum {
+ ACK_ACK,
+ ACK_NACK
+} CpiAckType;
+
+typedef struct control_plane_information {
+ CpiMessageType messageType;
+ CpiOperation operation;
+ uint64_t serialNumber;
+} ControlPlaneInformation;
+
+
+const char *cpiRequest_GetJsonTag();
+const char *cpiResponse_GetJsonTag();
+
+/**
+ * Return the name used in the JSON representation for a control message sequence number.
+ *
+ * @return The name used in the JSON representation for a control message sequence number.
+ *
+ * Example:
+ * @code
+ * {
+ **cpiSequence_GetJSONTag
+ * }
+ * @endcode
+ */
+const char *cpiSequence_GetJSONTag(void);
+
+/**
+ * Get the CpiOperation from the given JSON representation of the CPI command.
+ *
+ * @param [in] json A pointer to a valid PARCJSON instance.
+ *
+ * @return The CpiOperation specified in the JSON.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *sequenceNumberJSONName = cpiSequence_GetJSONTag();
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CpiOperation cpi_getCPIOperation2(const PARCJSON *json);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] control A pointer to a valid CCNxControl instance.
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CpiOperation cpi_GetMessageOperation(CCNxControl *control);
+
+/**
+ * Get the CpiMessageType from the given JSON representation of the CPIMessage
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CpiMessageType controlPlaneInterface_GetCPIMessageType(PARCJSON *json);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CpiMessageType cpi_GetMessageType(const CCNxControl *control);
+
+/**
+ * Get the sequence number of the given Control Plane Message.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+uint64_t controlPlaneInterface_GetSequenceNumber(const PARCJSON *controlPlaneMessage);
+
+/**
+ * All CPI messages carry a sequence number.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint64_t cpi_GetSequenceNumber(CCNxControl *control);
+
+/**
+ * Gererate a CPI request
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#define CPI_CURRENT_INTERFACE 0x7FFFFFFF
+
+/**
+ * Generate a control object to request the forewarder version
+ *
+ * Will cause a CPI Response to be sent back, if the forwarder supports the command.
+ * Otherwise, the ForwarderConnector should send a NACK back.
+ *
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxControl *cpi_ForwarderVersion(void);
+
+/**
+ * Cause the connection to pause input (from the top and bottom).
+ * When the ACk arrives back to the top, caller know there are no
+ * more data messages in the stack.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *cpi_CreatePauseInputRequest(void);
+
+/**
+ * Creates a message that the forwarder connector will ACK. Once the
+ * ACK with the corresponding sequence number is received, the sender knows
+ * that all prior messages had been handled by the forwarder connector.
+ *
+ * @return non-null An allocted JSON object
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *cpi_CreateFlushRequest(void);
+
+/**
+ * Given the inner operation member, wrap it in a Request with a sequence number
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *cpi_CreateRequest(const char *key, PARCJSON *operation);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CCNxControl *cpi_CreateResponse(CCNxControl *request, PARCJSON *response);
+
+/**
+ * Create an acknowledgement to the given request (expressed in JSON).
+ *
+ * @param [in] request A pointer to a PARCJSON representation of the request to acknowledge.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a PARCJSON instance representing the acknowledgement.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *cpiAcks_CreateAck(const PARCJSON *request);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *cpiAcks_CreateNack(const PARCJSON *request);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+bool cpiAcks_IsAck(const PARCJSON *json);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+uint64_t cpiAcks_GetAckOriginalSequenceNumber(const PARCJSON *json);
+#endif // libccnx_controlPlaneInterface_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Acks.c b/libccnx-transport-rta/ccnx/api/control/cpi_Acks.c
new file mode 100644
index 00000000..07bc934a
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_Acks.c
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+/**
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+/*
+ * {
+ * "CPI_ACK" : {
+ * "SEQUENCE" : <sequence number>,
+ * "RETURN" : "ACK" or "NACK",
+ * "REQUEST" : <original request JSON>
+ * [, "MESSAGE" : <optional message> ]
+ * }
+ * ["AUTHENTICATOR" : <TBD proof based on request/response, e.g. a crypto signature>]
+ * }
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <strings.h>
+
+#include <LongBow/runtime.h>
+
+#include "controlPlaneInterface.h"
+#include "cpi_private.h"
+#include "cpi_Acks.h"
+
+struct control_plane_ack {
+ ControlPlaneInformation cpi_ack;
+ CpiAckType ack_type;
+ ControlPlaneInformation cpi_original;
+};
+
+static const char *cpiReturn = "RETURN";
+static const char *cpiReturnAck = "ACK";
+static const char *cpiReturnNack = "NACK";
+static const char *cpiOriginal = "REQUEST";
+static const char *cpiRequest = "CPI_REQUEST";
+
+PARCJSON *
+cpiAcks_CreateAck(const PARCJSON *originalRequest)
+{
+ uint64_t seqnum = cpi_GetNextSequenceNumber();
+ PARCJSON *body = parcJSON_Create();
+
+ parcJSON_AddInteger(body, cpiSeqnum, (int) seqnum);
+ parcJSON_AddString(body, cpiReturn, cpiReturnAck);
+
+ PARCJSON *copy = parcJSON_Copy(originalRequest);
+ parcJSON_AddObject(body, cpiOriginal, copy);
+ parcJSON_Release(&copy);
+
+ PARCJSON *json = parcJSON_Create();
+
+ parcJSON_AddObject(json, cpiAck, body);
+ parcJSON_Release(&body);
+
+ return json;
+}
+
+PARCJSON *
+cpiAcks_CreateNack(const PARCJSON *request)
+{
+ uint64_t seqnum = cpi_GetNextSequenceNumber();
+ PARCJSON *body = parcJSON_Create();
+ parcJSON_AddInteger(body, cpiSeqnum, (int) seqnum);
+ parcJSON_AddString(body, cpiReturn, cpiReturnNack);
+
+ PARCJSON *copy = parcJSON_Copy(request);
+ parcJSON_AddObject(body, cpiOriginal, copy);
+ parcJSON_Release(&copy);
+
+ PARCJSON *json = parcJSON_Create();
+ parcJSON_AddObject(json, cpiAck, body);
+ parcJSON_Release(&body);
+
+ return json;
+}
+
+bool
+cpiAcks_IsAck(const PARCJSON *json)
+{
+ PARCJSONValue *ack_value = parcJSON_GetValueByName(json, cpiAck);
+ if (ack_value != NULL) {
+ PARCJSON *ack_json = parcJSONValue_GetJSON(ack_value);
+ PARCJSONValue *return_value = parcJSON_GetValueByName(ack_json, cpiReturn);
+ PARCBuffer *sBuf = parcJSONValue_GetString(return_value);
+ const char *returnStr = parcBuffer_Overlay(sBuf, 0);
+ return strcasecmp(returnStr, cpiReturnAck) == 0;
+ }
+ return false;
+}
+
+uint64_t
+cpiAcks_GetAckOriginalSequenceNumber(const PARCJSON *json)
+{
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpiAck);
+ assertNotNull(value, "got null ack json: %s", parcJSON_ToString(json));
+
+ PARCJSON *tempJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(tempJson, cpiOriginal);
+ assertNotNull(value, "got null original json from the ack: %s", parcJSON_ToString(tempJson));
+
+ tempJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(tempJson, cpiRequest);
+ assertNotNull(value, "got null request json from the ack: %s", parcJSON_ToString(tempJson));
+
+ tempJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(tempJson, cpiSeqnum);
+ assertNotNull(value, "got null seqnum inside the request: %s", parcJSON_ToString(tempJson));
+
+ return parcJSONValue_GetInteger(value);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Acks.h b/libccnx-transport-rta/ccnx/api/control/cpi_Acks.h
new file mode 100644
index 00000000..36ad0441
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_Acks.h
@@ -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.
+ */
+
+/**
+ * @file cpi_Acks.h
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#ifndef libccnx_cpi_Acks_h
+#define libccnx_cpi_Acks_h
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_JSON.h>
+
+struct control_plane_ack;
+typedef struct control_plane_ack CPIAck;
+
+#define cpiAck "CPI_ACK"
+#define cpiSeqnum "SEQUENCE"
+
+/**
+ * Create a CPIAck instance from a PARCJSON instance.
+ *
+ * @param [in] json A pointer to a valid PARCJSON instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a valid CPIAck instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+CPIAck *cpiAcks_ParseJSON(const PARCJSON *json);
+
+/**
+ * Create a CPIAck instance.
+ *
+ * @param [in] sequenceNumber The sequence number for the ACK.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a valid CPIAck instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+CPIAck *cpiAcks_Create(uint64_t sequenceNumber);
+
+/**
+ * Create a CPIAck instance, from a template of the original request.
+ *
+ * @param [in] originalRequest A pointer to a valid PARCJSON instance containint he original request.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a valid PARCJSON instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+PARCJSON *cpiAcks_CreateAck(const PARCJSON *originalRequest);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+PARCJSON *cpiAcks_CreateNack(const PARCJSON *request);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool cpiAcks_IsAck(const PARCJSON *json);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+uint64_t cpiAcks_GetAckOriginalSequenceNumber(const PARCJSON *json);
+#endif // libccnx_cpi_Acks_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Address.c b/libccnx-transport-rta/ccnx/api/control/cpi_Address.c
new file mode 100644
index 00000000..6dd44f69
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_Address.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 <config.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include <ccnx/api/control/cpi_Address.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Base64.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Network.h>
+
+#include <LongBow/runtime.h>
+
+const char *cpiAddressType = "ADDRESSTYPE";
+const char *cpiAddrData = "DATA";
+
+struct cpi_address {
+ CPIAddressType addressType;
+ PARCBuffer *blob;
+};
+
+static struct cpi_address_type_str {
+ CPIAddressType type;
+ const char *str;
+} cpiAddressTypeString[] = {
+ { .type = cpiAddressType_INET, .str = "INET" },
+ { .type = cpiAddressType_INET6, .str = "INET6" },
+ { .type = cpiAddressType_LINK, .str = "LINK" },
+ { .type = cpiAddressType_IFACE, .str = "IFACE" },
+ { .type = cpiAddressType_UNIX, .str = "UNIX" },
+ { .type = 0, .str = NULL }
+};
+
+void
+cpiAddress_Destroy(CPIAddress **addressPtr)
+{
+ assertNotNull(addressPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*addressPtr, "Parameter must dereference to non-null pointer");
+
+ CPIAddress *address = *addressPtr;
+ parcBuffer_Release(&address->blob);
+ parcMemory_Deallocate((void **) &address);
+ *addressPtr = NULL;
+}
+
+void
+cpiAddress_AssertValid(const CPIAddress *address)
+{
+ assertNotNull(address, "Parameter must be non-null CPIAddress *");
+}
+
+const char *
+cpiAddress_TypeToString(CPIAddressType type)
+{
+ for (int i = 0; cpiAddressTypeString[i].str != NULL; i++) {
+ if (cpiAddressTypeString[i].type == type) {
+ return cpiAddressTypeString[i].str;
+ }
+ }
+ trapIllegalValue(type, "Unknown value: %d", type);
+}
+
+CPIAddressType
+cpiAddress_StringToType(const char *str)
+{
+ for (int i = 0; cpiAddressTypeString[i].str != NULL; i++) {
+ if (strcasecmp(cpiAddressTypeString[i].str, str) == 0) {
+ return cpiAddressTypeString[i].type;
+ }
+ }
+ trapIllegalValue(str, "Unknown type '%s'", str);
+}
+
+static CPIAddress *
+_cpiAddress_Create(CPIAddressType addressType, PARCBuffer *buffer)
+{
+ CPIAddress *result = parcMemory_AllocateAndClear(sizeof(CPIAddress));
+
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIAddress));
+ if (result != NULL) {
+ result->addressType = addressType;
+ result->blob = buffer;
+ }
+ return result;
+}
+
+CPIAddress *
+cpiAddress_CreateFromInet(struct sockaddr_in *addr_in)
+{
+ assertNotNull(addr_in, "Parameter must be non-null");
+
+ addr_in->sin_family = AF_INET;
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in));
+ parcBuffer_PutArray(buffer, sizeof(struct sockaddr_in), (uint8_t *) addr_in);
+ parcBuffer_Flip(buffer);
+
+ CPIAddress *result = _cpiAddress_Create(cpiAddressType_INET, buffer);
+
+ return result;
+}
+
+CPIAddress *
+cpiAddress_CreateFromInet6(struct sockaddr_in6 *addr_in6)
+{
+ assertNotNull(addr_in6, "Parameter must be non-null");
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in6));
+ parcBuffer_PutArray(buffer, sizeof(struct sockaddr_in6), (uint8_t *) addr_in6);
+ parcBuffer_Flip(buffer);
+
+ CPIAddress *result = _cpiAddress_Create(cpiAddressType_INET6, buffer);
+
+ return result;
+}
+
+CPIAddress *
+cpiAddress_CreateFromLink(const uint8_t *linkaddr, size_t length)
+{
+ assertNotNull(linkaddr, "Parameter must be non-null");
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in6));
+ parcBuffer_PutArray(buffer, length, linkaddr);
+ parcBuffer_Flip(buffer);
+
+ CPIAddress *result = _cpiAddress_Create(cpiAddressType_LINK, buffer);
+ return result;
+}
+
+CPIAddress *
+cpiAddress_CreateFromInterface(unsigned interfaceIndex)
+{
+ unsigned netbyteorder = htonl(interfaceIndex);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(netbyteorder));
+ parcBuffer_PutArray(buffer, sizeof(netbyteorder), (uint8_t *) &netbyteorder);
+ parcBuffer_Flip(buffer);
+
+ CPIAddress *result = _cpiAddress_Create(cpiAddressType_IFACE, buffer);
+ return result;
+}
+
+CPIAddress *
+cpiAddress_CreateFromUnix(struct sockaddr_un *addr_un)
+{
+ assertNotNull(addr_un, "Parameter must be non-null");
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_un));
+ parcBuffer_PutArray(buffer, sizeof(struct sockaddr_un), (uint8_t *) addr_un);
+ parcBuffer_Flip(buffer);
+
+ CPIAddress *result = _cpiAddress_Create(cpiAddressType_UNIX, buffer);
+ return result;
+}
+
+CPIAddress *
+cpiAddress_Copy(const CPIAddress *original)
+{
+ cpiAddress_AssertValid(original);
+
+ CPIAddress *result = _cpiAddress_Create(original->addressType, parcBuffer_Copy(original->blob));
+ return result;
+}
+
+bool
+cpiAddress_Equals(const CPIAddress *a, const CPIAddress *b)
+{
+ if (a == b) {
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (a->addressType == b->addressType) {
+ if (parcBuffer_Equals(a->blob, b->blob)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+PARCJSON *
+cpiAddress_ToJson(const CPIAddress *address)
+{
+ cpiAddress_AssertValid(address);
+
+ PARCJSON *json = parcJSON_Create();
+ PARCBufferComposer *encoded = parcBase64_Encode(parcBufferComposer_Create(), address->blob);
+
+ // we need a NULL at the end of the string.
+ parcBufferComposer_PutUint8(encoded, 0);
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(encoded);
+ char *str = parcBuffer_Overlay(buffer, 0);
+
+ parcJSON_AddString(json, cpiAddressType, cpiAddress_TypeToString(address->addressType));
+ parcJSON_AddString(json, cpiAddrData, str);
+
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&encoded);
+
+ return json;
+}
+
+CPIAddress *
+cpiAddress_CreateFromJson(PARCJSON *json)
+{
+ assertNotNull(json, "Parameter must be non-null");
+
+ PARCJSONValue *addrFamilyValue = parcJSON_GetValueByName(json, cpiAddressType);
+
+ assertNotNull(addrFamilyValue, "json is not valid, missing %s: %s", cpiAddressType, parcJSON_ToString(json));
+ assertTrue(parcJSONValue_IsString(addrFamilyValue),
+ "%s key is not a number: %s", cpiAddressType, parcJSON_ToString(json));
+
+ PARCJSONValue *addrDataValue = parcJSON_GetValueByName(json, cpiAddrData);
+
+ assertNotNull(addrDataValue, "json is not valid, missing %s: %s", cpiAddrData, parcJSON_ToString(json));
+
+ PARCBufferComposer *composer =
+ parcBase64_Decode(parcBufferComposer_Create(), parcJSONValue_GetString(addrDataValue));
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ parcBufferComposer_Release(&composer);
+
+ PARCBuffer *sBuf = parcJSONValue_GetString(addrFamilyValue);
+
+ CPIAddress *result =
+ _cpiAddress_Create(cpiAddress_StringToType(parcBuffer_Overlay(sBuf, 0)), buffer);
+
+ return result;
+}
+
+CPIAddressType
+cpiAddress_GetType(const CPIAddress *address)
+{
+ cpiAddress_AssertValid(address);
+
+ return address->addressType;
+}
+
+// The Get functions need better names, what they do (Get from what? Put to what?)
+// is not clear from their names. Case 1028
+bool
+cpiAddress_GetInet(const CPIAddress *address, struct sockaddr_in *addr_in)
+{
+ cpiAddress_AssertValid(address);
+ assertNotNull(addr_in, "Parameter addr_in must be non-null");
+
+ if (address->addressType == cpiAddressType_INET) {
+ assertTrue(parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_in),
+ "CPIAddress corrupted. Expected length %zu, actual length %zu",
+ sizeof(struct sockaddr_in),
+ parcBuffer_Remaining(address->blob));
+
+ memcpy(addr_in, parcBuffer_Overlay(address->blob, 0), sizeof(struct sockaddr_in));
+ return true;
+ }
+ return false;
+}
+
+bool
+cpiAddress_GetInet6(const CPIAddress *address, struct sockaddr_in6 *addr_in6)
+{
+ cpiAddress_AssertValid(address);
+ assertNotNull(addr_in6, "Parameter addr_in6 must be non-null");
+
+ if (address->addressType == cpiAddressType_INET6) {
+ assertTrue(parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_in6),
+ "CPIAddress corrupted. Expected length %zu, actual length %zu",
+ sizeof(struct sockaddr_in6),
+ parcBuffer_Remaining(address->blob));
+
+ memcpy(addr_in6, parcBuffer_Overlay(address->blob, 0), sizeof(struct sockaddr_in6));
+ return true;
+ }
+ return false;
+}
+
+bool
+cpiAddress_GetUnix(const CPIAddress *address, struct sockaddr_un *addr_un)
+{
+ cpiAddress_AssertValid(address);
+ assertNotNull(addr_un, "Parameter addr_in6 must be non-null");
+
+ if (address->addressType == cpiAddressType_UNIX) {
+ assertTrue(parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_un),
+ "CPIAddress corrupted. Expected length %zu, actual length %zu",
+ sizeof(struct sockaddr_un),
+ parcBuffer_Remaining(address->blob));
+
+ memcpy(addr_un, parcBuffer_Overlay(address->blob, 0), sizeof(struct sockaddr_un));
+ return true;
+ }
+ return false;
+}
+
+bool
+cpiAddress_GetInterfaceIndex(const CPIAddress *address, uint32_t *ifidx)
+{
+ cpiAddress_AssertValid(address);
+ assertNotNull(ifidx, "Parameter ifidx must be non-null");
+
+ if (address->addressType == cpiAddressType_IFACE) {
+ assertTrue(parcBuffer_Remaining(address->blob) == sizeof(uint32_t),
+ "CPIAddress corrupted. Expected length %zu, actual length %zu",
+ sizeof(uint32_t),
+ parcBuffer_Remaining(address->blob));
+
+ uint32_t netbyteorder;
+ memcpy(&netbyteorder, parcBuffer_Overlay(address->blob, 0), sizeof(uint32_t));
+ *ifidx = ntohl(netbyteorder);
+ return true;
+ }
+ return false;
+}
+
+PARCBuffer *
+cpiAddress_GetLinkAddress(const CPIAddress *address)
+{
+ cpiAddress_AssertValid(address);
+ if (address->addressType == cpiAddressType_LINK) {
+ return address->blob;
+ }
+ return NULL;
+}
+
+static PARCBufferComposer *
+_Inet_BuildString(const CPIAddress *address, PARCBufferComposer *composer)
+{
+ cpiAddress_AssertValid(address);
+
+ struct sockaddr_in *saddr = (struct sockaddr_in *) parcBuffer_Overlay(address->blob, 0);
+ return parcNetwork_SockInet4Address_BuildString(saddr, composer);
+}
+
+static PARCBufferComposer *
+_Inet6_BuildString(const CPIAddress *address, PARCBufferComposer *composer)
+{
+ cpiAddress_AssertValid(address);
+
+ struct sockaddr_in6 *saddr = (struct sockaddr_in6 *) parcBuffer_Overlay(address->blob, 0);
+ return parcNetwork_SockInet6Address_BuildString(saddr, composer);
+}
+
+static PARCBufferComposer *
+_Link_BuildString(const CPIAddress *address, PARCBufferComposer *composer)
+{
+ cpiAddress_AssertValid(address);
+
+ const unsigned char *addr = parcBuffer_Overlay(address->blob, 0);
+
+ size_t length = parcBuffer_Remaining(address->blob);
+
+ return parcNetwork_LinkAddress_BuildString(addr, length, composer);
+}
+
+static ssize_t
+_UnixToString(char *output, size_t remaining_size, const PARCBuffer *addr)
+{
+ assertNotNull(output, "parameter output must be non-null");
+ parcBuffer_AssertValid(addr);
+
+ assertTrue(parcBuffer_Remaining(addr) == sizeof(struct sockaddr_un),
+ "CPIAddress corrupted. Expected %zu actual %zu",
+ sizeof(struct sockaddr_un), parcBuffer_Remaining(addr));
+
+ // sockaddr length for the path, 16 for the ascii stuff, 3 for the length number
+ struct sockaddr_un *saddr = (struct sockaddr_un *) parcBuffer_Overlay((PARCBuffer *) addr, 0);
+ size_t min_remaining = strlen(saddr->sun_path) + 16 + 3;
+ assertTrue(remaining_size >= min_remaining,
+ "Remaining size too small, need at least %zu", min_remaining);
+
+ ssize_t output_length = sprintf(output, "{ .path=%s, .len=%zu }", saddr->sun_path, strlen(saddr->sun_path));
+ return output_length;
+}
+
+static ssize_t
+_IfaceToString(char *output, size_t remaining_size, const PARCBuffer *addr)
+{
+ assertNotNull(output, "parameter output must be non-null");
+ parcBuffer_AssertValid(addr);
+
+ assertTrue(parcBuffer_Remaining(addr) == sizeof(uint32_t),
+ "CPIAddress corrupted. Expected %zu actual %zu",
+ sizeof(uint32_t), parcBuffer_Remaining(addr));
+
+ uint32_t *ifidx = (uint32_t *) parcBuffer_Overlay((PARCBuffer *) addr, 0);
+
+ ssize_t output_length = sprintf(output, "{ .ifidx=%u }", ntohl(*ifidx));
+
+ return output_length;
+}
+
+PARCBufferComposer *
+cpiAddress_BuildString(const CPIAddress *address, PARCBufferComposer *composer)
+{
+ if (address != NULL) {
+ char *str = cpiAddress_ToString(address);
+ parcBufferComposer_PutString(composer, str);
+ parcMemory_Deallocate((void **) &str);
+ }
+ return composer;
+}
+
+char *
+cpiAddress_ToString(const CPIAddress *address)
+{
+ cpiAddress_AssertValid(address);
+
+ char addrstr[256];
+
+ switch (address->addressType) {
+ case cpiAddressType_INET: {
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(_Inet_BuildString(address, composer));
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ return result;
+ }
+ break;
+
+ case cpiAddressType_INET6: {
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(_Inet6_BuildString(address, composer));
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ parcBufferComposer_Release(&composer);
+ return result;
+ }
+ break;
+
+ case cpiAddressType_UNIX:
+ _UnixToString(addrstr, 256, address->blob);
+ break;
+
+ case cpiAddressType_LINK: {
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(_Link_BuildString(address, composer));
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ parcBufferComposer_Release(&composer);
+ return result;
+ }
+ break;
+
+ case cpiAddressType_IFACE:
+ _IfaceToString(addrstr, 256, address->blob);
+ break;
+
+ default:
+ sprintf(addrstr, "UNKNOWN type = %d", address->addressType);
+ break;
+ }
+
+ ssize_t alloc_size = 1024;
+ char *output = parcMemory_Allocate(alloc_size);
+ assertNotNull(output, "parcMemory_Allocate(%zu) returned NULL", alloc_size);
+ ssize_t output_length = snprintf(output, alloc_size, "{ .type=%s, .data=%s }", cpiAddress_TypeToString(address->addressType), addrstr);
+
+ assertTrue(output_length < alloc_size, "allocated size too small, needed %zd", output_length);
+ assertFalse(output_length < 0, "snprintf error: (%d) %s", errno, strerror(errno));
+
+ return output;
+}
+
+PARCHashCode
+cpiAddress_HashCode(const CPIAddress *address)
+{
+ cpiAddress_AssertValid(address);
+
+ PARCHashCode hash = parcBuffer_HashCode(address->blob);
+ hash = parcHashCode_HashImpl((uint8_t *) &address->addressType, sizeof(address->addressType), hash);
+
+ return hash;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Address.h b/libccnx-transport-rta/ccnx/api/control/cpi_Address.h
new file mode 100644
index 00000000..94a7b0ca
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_Address.h
@@ -0,0 +1,599 @@
+/*
+ * 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 cpi_Address.h
+ * @brief Represents an endpoint address.
+ *
+ * Represents an endpoint address. May be INET, INET6, or a multi-byte LINK,
+ * or an Interface Index.
+ *
+ * INET and INET6 must contain the .sa_addr member, and other members as needed
+ * by the use of the address.
+ *
+ * The Interface Index address is essentially a pointer to a device.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#ifndef libccnx_cpi_Address_h
+#define libccnx_cpi_Address_h
+
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+typedef enum {
+ cpiAddressType_INET = 1,
+ cpiAddressType_INET6 = 2,
+ cpiAddressType_LINK = 3,
+ cpiAddressType_IFACE = 4,
+ cpiAddressType_UNIX = 5 /* PF_UNIX */
+} CPIAddressType;
+
+/**
+ * Return a string representation of the given `CPIAddressType`
+ *
+ * @param [in] type A valid CPIAddressType value.
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a static string representation of the `CPIAddressType`.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *typeAsString = cpiAddress_TypeToString(cpiAddressType_INET);
+ * }
+ * @endcode
+ *
+ * @see cpiAddress_StringToType
+ */
+const char *cpiAddress_TypeToString(CPIAddressType type);
+
+/**
+ * Return a `CPIAddressType` from the given nul-terminated C string.
+ *
+ * This induces a LongBow trap for an illegal value.
+ *
+ * @param [in] typeAsString A nul-terminated, C string representation of a `CPIAddressType`.
+ *
+ * @return A CPIAddressType
+ *
+ * Example:
+ * @code
+ * {
+ * CPIAddressType type = cpiAddress_TypeToString("INET");
+ * }
+ * @endcode
+ *
+ * @see cpiAddress_TypeToString
+ */
+CPIAddressType cpiAddress_StringToType(const char *typeAsString);
+
+struct cpi_address;
+typedef struct cpi_address CPIAddress;
+
+/**
+ * Create a new `CPIAddress` instance from an IPv4 IP address, the port is optional.
+ *
+ * The sockaddr_in should be filled in network byte order. The newly created instance must
+ * eventually be destroyed by calling {@link cpiAddress_Destroy}().
+ *
+ * @param [in] addr_in The `sockaddr_in` representing the IPv4 IP address with which to initialize the new `CPIAddress` instance.
+ * @return A new instance of `CPIAddress` that must eventually be destroyed by calling {@link cpiAddress_Destroy}().
+ *
+ * Example:
+ * @code
+ * {
+ * CPIAddress *dest = cpiAddress_CreateFromInet(
+ * &(struct sockaddr_in) {
+ * .sa_addr = inet_addr("foo.bar.com"),
+ * .sa_port = htons(9695) } );
+ * cpiAddress_Destroy(&dest);
+ * }
+ * @endcode
+ * @see cpiAddress_Destroy
+ */
+CPIAddress *cpiAddress_CreateFromInet(struct sockaddr_in *addr_in);
+
+/**
+ * Create a new `CPIAddress` instance from an IPv6 IP address, the port is optional.
+ *
+ *
+ * The sockaddr_in should be filled in network byte order. The newly created instance must
+ * eventually be destroyed by calling {@link cpiAddress_Destroy}().
+ *
+ * @param [in] addr_in6 A `sockaddr_in6` from which to initialize a new instance of CPIAddress
+ * @return A new instance of `CPIAddress` that must eventually be destroyed by calling {@link cpiAddress_Destroy}()
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr_in6 addr_in6;
+ * memset(&addr_in6, 0, sizeof(struct sockaddr_in6));
+ *
+ * inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr));
+ * addr_in6.sin6_family = AF_INET6;
+ * addr_in6.sin6_port = 0x0A0B;
+ * addr_in6.sin6_flowinfo = 0x01020304;
+ *
+ * CPIAddress *address = cpiAddress_CreateFromInet6(&addr_in6);
+ *
+ * cpiAddress_Destroy(&address);
+ * }
+ * @endcode
+ * @see cpiAddress_Destroy
+ */
+CPIAddress *cpiAddress_CreateFromInet6(struct sockaddr_in6 *addr_in6);
+
+/**
+ * Create a new `CPIAddress` instance, initialized from a Link address.
+ *
+ * User must know the link address format (i.e. token ring vs ethernet) and have the address in a byte array.
+ * The array is encoded in left-to-right order. The newly created instance must eventually be destroyed by
+ * calling {@link cpiAddress_Destroy}().
+ *
+ * @param [in] linkaddr A byte array containing the link address
+ * @param [in] length The length of the link address byte array
+ * @return A new instance of `CPIAddress` that must eventually be destroyed by calling {@link cpiAddress_Destroy}()
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t mac[] = { 0x14, 0x10, 0x9f, 0xd7, 0x0b, 0x89 };
+ * CPIAddress *address = cpiAddress_CreateFromLink(mac, sizeof(mac));
+ *
+ * cpiAddress_Destroy(&address);
+ * }
+ * @endcode
+ * @see cpiAddress_Destroy
+ */
+CPIAddress *cpiAddress_CreateFromLink(const uint8_t *linkaddr, size_t length);
+
+/**
+ * Create a new `CPIAddress` instance from a network interface index.
+ *
+ * The interfaceIndex should be in host byte order. The newly created instance must eventually be destroyed by
+ * calling {@link cpiAddress_Destroy}().
+ *
+ * @param [in] interfaceIndex The index of the interface to encode
+ * @return A new instance of `CPIAddress` that must eventually be destroyed by calling {@link cpiAddress_Destroy}()
+ *
+ * Example:
+ * @code
+ * {
+ * CPIAddress *address = cpiAddress_CreateFromInterface(2);
+ *
+ * cpiAddress_Destroy(&address);
+ * }
+ * @endcode
+ * @see cpiAddress_Destroy
+ */
+CPIAddress *cpiAddress_CreateFromInterface(uint32_t interfaceIndex);
+
+/**
+ * Create a new CPIAddress instance from a PF_UNIX address domain.
+ *
+ * The newly created instance must eventually be destroyed by calling {@link cpiAddress_Destroy}().
+ *
+ * @param [in] addr_un The `struct sockaddr_un` specifying the local PF_UNIX socket address
+ * @return A new instance of `CPIAddress` that must eventually be destroyed by calling {@link cpiAddress_Destroy}()
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr_un addr_unix;
+ * memset(&addr_unix, 0, sizeof(struct sockaddr_un));
+ * char path[] = "/Hello/Cruel/World";
+ * strcpy(addr_un.sun_path, path);
+ * addr_un.sun_family = AF_UNIX;
+ *
+ * CPIAddress *address = cpiAddress_CreateFromUnix(&addr_un);
+ *
+ * cpiAddress_Destroy(&address);
+ * }
+ * @endcode
+ * @see cpiAddress_Destroy
+ */
+CPIAddress *cpiAddress_CreateFromUnix(struct sockaddr_un *addr_un);
+
+/**
+ * Create a deep copy of an instance of a `CPIAddress`. A completely new, indedependent instance is created.
+ *
+ * The newly created instance must eventually be destroyed by calling {@link cpiAddress_Destroy}().
+ *
+ * @param [in] original A pointer to a `CPIAddress` instance to be copied.
+ * @return A new instance of a CPIAddress, deep copied from the `original` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIAddress *address = cpiAddress_CreateFromInterface(2);
+ *
+ * CPIAddress *copy = cpiAddress_Copy(address);
+ *
+ * cpiAddress_Destroy(&address);
+ * cpiAddress_Destroy(&copy);
+ * }
+ * @endcode
+ * @see cpiAddress_Destroy
+ */
+CPIAddress *cpiAddress_Copy(const CPIAddress *original);
+
+/**
+ * Deallocate an instance of a CPIAddress.
+ *
+ * The CPIAddress instance is deallocated, and any referenced data is also deallocated.
+ * The referenced pointer is set to NULL upon return.
+ *
+ * @param [in] addressPtr A pointer to a pointer to an instance of CPIAddress.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIAddress *address = cpiAddress_CreateFromInterface(2);
+ *
+ * cpiAddress_Destroy(&address);
+ * }
+ * @endcode
+ */
+void cpiAddress_Destroy(CPIAddress **addressPtr);
+
+/**
+ * Create a new PARCJSON instance representing the specified `CPIAddress` instance.
+ *
+ * The newly created PARCJSON instance must eventually be destroyed by calling {@link parcJSON_Release}().
+ *
+ * @param [in] address A pointer to a CPIAddress instance.
+ * @return A new PARCJSON instance representing the specified `address`.
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr_in6 addr_in6;
+ * memset(&addr_in6, 0, sizeof(struct sockaddr_in6));
+ *
+ * inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr));
+ * addr_in6.sin6_family = AF_INET6;
+ * addr_in6.sin6_port = 0x0A0B;
+ * addr_in6.sin6_flowinfo = 0x01020304;
+ *
+ * CPIAddress *address = cpiAddress_CreateFromInet6(&addr_in6);
+ *
+ * PARCJSON *json = cpiAddress_ToJson(address);
+ *
+ * CPIAddress *address2 = cpiAddress_CreateFromJson(json);
+ *
+ * cpiAddress_Destroy(&address);
+ * cpiAddress_Destroy(&address2);
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *cpiAddress_ToJson(const CPIAddress *address);
+
+/**
+ * Create a new PARCJSON instance from a JSON description of an address.
+ *
+ * The JSON passed in should look like `{ "LABEL" : { "ADDRESSTYPE" : integer, "DATA" : base_64_data } }`.
+ * The newly created PARCJSON instance must eventually be destroyed by calling {@link parcJSON_Release}().
+ *
+ * The value of "LABEL" does not matter, but the inner structure must be as specified.
+ *
+ * The ADDRESSTYPE is one of {@link CPIAddressType}.
+ *
+ * @param [in] json A pointer to a PARCJSON instance describing an address
+ * @return A newly created CPIAddress instance
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr_in6 addr_in6;
+ * memset(&addr_in6, 0, sizeof(struct sockaddr_in6));
+ *
+ * inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr));
+ * addr_in6.sin6_family = AF_INET6;
+ * addr_in6.sin6_port = 0x0A0B;
+ * addr_in6.sin6_flowinfo = 0x01020304;
+ *
+ * CPIAddress *address = cpiAddress_CreateFromInet6(&addr_in6);
+ *
+ * PARCJSON *json = cpiAddress_ToJson(address);
+ *
+ * CPIAddress *address2 = cpiAddress_CreateFromJson(json);
+ *
+ * cpiAddress_Destroy(&address);
+ * cpiAddress_Destroy(&address2);
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ */
+CPIAddress *cpiAddress_CreateFromJson(PARCJSON *json);
+
+/**
+ * Determine if two CPIAddress instances are equal.
+ *
+ *
+ * The following equivalence relations on non-null `CPIAddress` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `cpiAddress_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `cpiAddress_Equals(x, y)` must return true if and only if
+ * `cpiAddress_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiAddress_Equals(x, y)` returns true and
+ * `cpiAddress_Equals(y, z)` returns true,
+ * then `cpiAddress_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `cpiAddress_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `cpiAddress_Equals(x, NULL)` must
+ * return false.
+ *
+ * If one address specifies more information than other,
+ * e.g. a is INET with a port and b is not, they are not equal.
+ *
+ * `a` and `b` may be NULL, and NULL == NULL.
+ *
+ * @param a A pointer to a CPIAddress instance
+ * @param b A pointer to a CPIAddress instance
+ * @return true if the two instances are equal
+ * @return false if the two instances are not equal
+ *
+ * Example:
+ * @code
+ * {
+ * CPIAddress *address = cpiAddress_CreateFromInterface(2);
+ * CPIAddress *copy = cpiAddress_Copy(address);
+ *
+ * if (cpiAddress_Equals(address, copy)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ *
+ * cpiAddress_Destroy(&address);
+ * cpiAddress_Destroy(&copy);
+ * }
+ * @endcode
+ */
+bool cpiAddress_Equals(const CPIAddress *a, const CPIAddress *b);
+
+/**
+ * Return the {@link CPIAddressType} from a specified CPIAddress.
+ *
+ * @param [in] A pointer to a CPIAddress instance
+ *
+ * @return the {@link CPIAddressType} of the specified CPIAddress instance
+ *
+ * Example:
+ * @code
+ * {
+ * CPIAddress *address = cpiAddress_CreateFromInterface(2);
+ *
+ * CPIAddressType type = cpiAddress_GetType(address);
+ *
+ * cpiAddress_Destroy(&address);
+ * }
+ * @endcode
+ *
+ * @see CPIAddressType
+ */
+CPIAddressType cpiAddress_GetType(const CPIAddress *address);
+
+/**
+ * Fills in the output parameter with an INET address.
+ *
+ * @param addr_in must be non-NULL
+ * @return true if INET address and output filled in, false otherwise.
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr_in6 addr_in6;
+ * memset(&addr_in6, 0, sizeof(struct sockaddr_in6));
+ *
+ * inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr));
+ * addr_in6.sin6_family = AF_INET6;
+ * addr_in6.sin6_port = 0x0A0B;
+ * addr_in6.sin6_flowinfo = 0x01020304;
+ *
+ * CPIAddress *address = cpiAddress_CreateFromInet6(&addr_in6);
+ *
+ * struct sockaddr_in6 addr_test;
+ * bool success = cpiAddress_GetInet6(address, &addr_test);
+ *
+ * cpiAddress_Destroy(&address);
+ * }
+ * @endcode
+ */
+bool cpiAddress_GetInet(const CPIAddress *address, struct sockaddr_in *addr_in);
+
+/**
+ * Retrieve the INET6 address associated with a `CPIAddress` instance.
+ *
+ * If the specified CPIAddress instance is of type {@link cpiAddressType_INET6}, then
+ * populate the supplied `struct sockaddr_in6` from the CPIAddress and return true. If the
+ * CPIAddress is not of type `cpiAddressType_INET6`, this function returns false.
+ *
+ * @param [in] address A pointer to a `CPIAddress` instance of type {@link cpiAddressType_INET6}.
+ * @param [in] addr_in6 A pointer to a `struct sockaddr_in6`. Must be non-NULL.
+ * @return true If the CPIAddress instance is of type `cpiAddressType_INET6` and `addr_in6` was filled in
+ * @return false If the CPIAddress instance was not of type `cpiAddressType_INET6` or `addr_in6` could not be filled in.
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr_in6 addr_in6;
+ * memset(&addr_in6, 0, sizeof(struct sockaddr_in6));
+ *
+ * inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr));
+ * addr_in6.sin6_family = AF_INET6;
+ * addr_in6.sin6_port = 0x0A0B;
+ * addr_in6.sin6_flowinfo = 0x01020304;
+ *
+ * CPIAddress *address = cpiAddress_CreateFromInet6(&addr_in6);
+ *
+ * struct sockaddr_in6 addr_test;
+ * bool success = cpiAddress_GetInet6(address, &addr_test);
+ *
+ * cpiAddress_Destroy(&address);
+ * }
+ * @endcode
+ * @see cpiAddress_GetType
+ */
+bool cpiAddress_GetInet6(const CPIAddress *address, struct sockaddr_in6 *addr_in6);
+
+/**
+ * Retrieve the interface index associated with a `CPIAddress` instance.
+ *
+ * If the specified `CPIAddress` instance is of type {@link cpiAddressType_IFACE}, then
+ * populate the supplied `uint32_t` from the CPIAddress and return true. If the
+ * `CPIAddress` is not of type `cpiAddressType_INET6`, this function returns false.
+ *
+ * @param [in] address A pointer to a `CPIAddress` instance of type {@link cpiAddressType_IFACE}.
+ * @param [in] interfaceIndex A pointer to a `uint32_t` to fill in. Must be non-NULL.
+ * @return true If the CPIAddress instance is of type `cpiAddressType_IFACE` and `interfaceIndex` was filled in.
+ * @return false If the CPIAddress instance was not of type `cpiAddressType_IFACE` or `interfaceIndex` could not be filled in.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIAddress *address = cpiAddress_CreateFromInterface(6);
+ *
+ * uint32_t test;
+ * bool success = cpiAddress_GetInterfaceIndex(address, &test);
+ *
+ * cpiAddress_Destroy(&address);
+ * }
+ * @endcode
+ * @see cpiAddress_GetType
+ */
+bool cpiAddress_GetInterfaceIndex(const CPIAddress *address, uint32_t *interfaceIndex);
+
+/**
+ * Retrieve the link address associated with a `CPIAddress` instance.
+ *
+ * If the specified `CPIAddress` instance is of type {@link cpiAddressType_LINK}, then return a pointer
+ * to the {@link PARCBuffer} containing the link address. If the `CPIAddress` is not of type {@link cpiAddressType_LINK},
+ * then return NULL. The returned PARCBuffer pointer points to memory managed by the CPIAddress instance, and
+ * does not need to be destroyed or released on its own.
+ *
+ * @param [in] address A pointer to a `CPIAddress` instance of type {@link cpiAddressType_LINK}.
+ * @return A pointer to the {@link PARCBuffer} containing the link address.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t mac[] = { 0x14, 0x10, 0x9f, 0xd7, 0x0b, 0x89 };
+ * CPIAddress *address = cpiAddress_CreateFromLink(mac, sizeof(mac));
+ *
+ * PARCBuffer *macBuffer = cpiAddress_GetLinkAddress(address);
+ *
+ * cpiAddress_Destroy(&address);
+ * }
+ * @endcode
+ * @see cpiAddress_GetType
+ */
+PARCBuffer *cpiAddress_GetLinkAddress(const CPIAddress *address);
+
+/**
+ * Append the string representation of a `CPIAddress` to a specified `PARCBufferComposer`.
+ *
+ * @param [in] address A pointer to a `CPIAddress` instance.
+ * @param [in] composer A pointer to a `PARCBufferComposer` instance to which to append the string.
+ *
+ * @return The `PARCBufferComposer` instance that was passed in.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIAddress *address = cpiAddress_CreateFromInterface(1);
+ * PARCBufferComposer *composer = cpiAddress_BuildString(address, parcBufferComposer_Create());
+ * parcBufferComposer_Release(&composer);
+ * cpiAddress_Destroy(&address);
+ * }
+ * @endcode
+ *
+ * @see PARCBufferComposer
+ */
+PARCBufferComposer *cpiAddress_BuildString(const CPIAddress *address, PARCBufferComposer *composer);
+
+/**
+ * Produce a nil-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 {@link parcMemory_Deallocate}().
+ *
+ * Example:
+ * @code
+ * {
+ * CPIAddress *address = cpiAddress_CreateFromInterface(1);
+ *
+ * char *string = cpiAddress_ToString(address);
+ *
+ * if (string != NULL) {
+ * printf("CPIAddress looks like: %s\n", string);
+ * parcMemory_Deallocate(string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * cpiAddress_Destroy(&address);
+ * }
+ * @endcode
+ * @see parcMemory_Deallocate
+ * @see cpiAddress_BuildString
+ */
+char *cpiAddress_ToString(const CPIAddress *address);
+
+/**
+ * Return a non-cryptographic hash code consistent with Equals
+ *
+ * If cpiAddressA == cpiAddressB, then cpiAddress_HashCode(cpiAddressA) == cpiAddress_HashCode(cpiAddressB)
+ *
+ * @param [in] address A pointer to a CPIAddress instance.
+ * @return A 32-bit hashcode for the specified CPIAddress instance.
+ *
+ * Example:
+ * @code
+ * CPIAddress *address = cpiAddress_CreateFromInterface(1);
+ *
+ * uint32_t hashCode = cpiAddress_HashCode(address);
+ *
+ * cpiAddress_Destroy(&address);
+ * @endcode
+ */
+PARCHashCode cpiAddress_HashCode(const CPIAddress *address);
+#endif // libccnx_cpi_Address_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_AddressList.c b/libccnx-transport-rta/ccnx/api/control/cpi_AddressList.c
new file mode 100644
index 00000000..a33800ad
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_AddressList.c
@@ -0,0 +1,206 @@
+/*
+ * 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/api/control/cpi_AddressList.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Buffer.h>
+
+struct cpi_addresslist {
+ PARCArrayList *listOfCPIAddress;
+};
+
+static void
+_cpiAddressList_FreeAddress(void **addressVoidPtr)
+{
+ CPIAddress **addressPtr = (CPIAddress **) addressVoidPtr;
+ cpiAddress_Destroy(addressPtr);
+}
+
+CPIAddressList *
+cpiAddressList_Create()
+{
+ CPIAddressList *list = parcMemory_AllocateAndClear(sizeof(CPIAddressList));
+ assertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIAddressList));
+ list->listOfCPIAddress = parcArrayList_Create(_cpiAddressList_FreeAddress);
+ assertNotNull(list->listOfCPIAddress, "Got null from parcArrayList_Create");
+
+ return list;
+}
+
+void
+cpiAddressList_Destroy(CPIAddressList **addressListPtr)
+{
+ assertNotNull(addressListPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*addressListPtr, "Parameter must dereference to non-null pointer");
+ CPIAddressList *list = *addressListPtr;
+
+ parcArrayList_Destroy(&list->listOfCPIAddress);
+ parcMemory_Deallocate((void **) &list);
+ *addressListPtr = NULL;
+}
+
+CPIAddressList *
+cpiAddressList_Append(CPIAddressList *list, CPIAddress *address)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ assertNotNull(address, "Parameter address must be non-null");
+
+ parcArrayList_Add(list->listOfCPIAddress, (PARCObject *) address);
+ return list;
+}
+
+CPIAddressList *
+cpiAddressList_Copy(const CPIAddressList *original)
+{
+ assertNotNull(original, "Parameter must be non-null");
+
+ CPIAddressList *copy = cpiAddressList_Create();
+ for (int i = 0; i < parcArrayList_Size(original->listOfCPIAddress); i++) {
+ CPIAddress *address = (CPIAddress *) parcArrayList_Get(original->listOfCPIAddress, i);
+ parcArrayList_Add(copy->listOfCPIAddress, (PARCObject *) cpiAddress_Copy(address));
+ }
+
+ return copy;
+}
+
+bool
+cpiAddressList_Equals(const CPIAddressList *a, const CPIAddressList *b)
+{
+ assertNotNull(a, "Parameter a must be non-null");
+ assertNotNull(b, "Parameter b must be non-null");
+
+ if (a == b) {
+ return true;
+ }
+
+ if (parcArrayList_Size(a->listOfCPIAddress) != parcArrayList_Size(b->listOfCPIAddress)) {
+ return false;
+ }
+
+ for (size_t i = 0; i < parcArrayList_Size(a->listOfCPIAddress); i++) {
+ const CPIAddress *addr_a = (CPIAddress *) parcArrayList_Get(a->listOfCPIAddress, i);
+ const CPIAddress *addr_b = (CPIAddress *) parcArrayList_Get(b->listOfCPIAddress, i);
+ if (!cpiAddress_Equals(addr_a, addr_b)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+size_t
+cpiAddressList_Length(const CPIAddressList *list)
+{
+ assertNotNull(list, "Parameter must be non-null");
+ return parcArrayList_Size(list->listOfCPIAddress);
+}
+
+const CPIAddress *
+cpiAddressList_GetItem(const CPIAddressList *list, size_t item)
+{
+ assertNotNull(list, "Parameter must be non-null");
+ assertTrue(item < cpiAddressList_Length(list), "Asked for item %zu beyond end of list %zu", item, cpiAddressList_Length(list));
+
+ return (CPIAddress *) parcArrayList_Get(list->listOfCPIAddress, item);
+}
+
+/**
+ * Returns a JSON array of the addresses
+ *
+ * { [ {addr0}, {addr1}, ..., {addrN} ] }
+ *
+ * @param <#param1#>
+ * @return A JSON array, even if array empty
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSONArray *
+cpiAddressList_ToJson(const CPIAddressList *list)
+{
+ assertNotNull(list, "Parameter must be non-null");
+ PARCJSONArray *array = parcJSONArray_Create();
+
+ for (size_t i = 0; i < cpiAddressList_Length(list); i++) {
+ const CPIAddress *addr = cpiAddressList_GetItem(list, i);
+ PARCJSON *json = cpiAddress_ToJson(addr);
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ parcJSON_Release(&json);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+ }
+
+ return array;
+}
+
+/**
+ * Creates an address list based on a JSON array
+ *
+ * { [ {addr0}, {addr1}, ..., {addrN} ] }
+ *
+ * @param <#param1#>
+ * @return An allocated address list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+CPIAddressList *
+cpiAddressList_CreateFromJson(PARCJSONArray *array)
+{
+ assertNotNull(array, "Parameter must be non-null");
+ CPIAddressList *list = cpiAddressList_Create();
+
+ for (size_t i = 0; i < parcJSONArray_GetLength(array); i++) {
+ PARCJSONValue *value = parcJSONArray_GetValue(array, i);
+ PARCJSON *addrjson = parcJSONValue_GetJSON(value);
+ CPIAddress *addr = cpiAddress_CreateFromJson(addrjson);
+ cpiAddressList_Append(list, addr);
+ }
+
+ return list;
+}
+
+char *
+cpiAddressList_ToString(const CPIAddressList *list)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ for (size_t i = 0; i < cpiAddressList_Length(list); i++) {
+ char *addressString = cpiAddress_ToString(cpiAddressList_GetItem(list, i));
+ parcBufferComposer_PutString(composer, addressString);
+ if (i < (cpiAddressList_Length(list) - 1)) {
+ parcBufferComposer_PutString(composer, " ");
+ }
+ parcMemory_Deallocate((void **) &addressString);
+ }
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(buffer);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_AddressList.h b/libccnx-transport-rta/ccnx/api/control/cpi_AddressList.h
new file mode 100644
index 00000000..235531f9
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_AddressList.h
@@ -0,0 +1,222 @@
+/*
+ * 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 cpi_AddressList.h
+ * @brief A list of CPIAddress instances.
+ *
+ * An AddressList is a list of addresses.
+ * It wraps a PARCLinkedList for type saftey with CPIAddress.
+ *
+ */
+#ifndef libccnx_cpi_AddressList_h
+#define libccnx_cpi_AddressList_h
+
+#include <ccnx/api/control/cpi_Address.h>
+
+struct cpi_addresslist;
+/**
+ * @typedef CPIAddressList
+ * @abstract A list of CPIAddress instance pointers.
+ */
+typedef struct cpi_addresslist CPIAddressList;
+
+/**
+ * Create an instance of {@link CPIAddressList}
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a valid CPIAddressList instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIAddressList *list = cpiAddressList_Create();
+ *
+ * }
+ * @endcode
+ *
+ * @see cpiAddressList_Destroy
+ */
+CPIAddressList *cpiAddressList_Create(void);
+
+/**
+ * Dellocate and destroy a CPIAddressList instance.
+ *
+ * @param [in] addressListPtr A pointer to a pointer to a valid {@link CPIAddressList}.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * CPIAddressList *list = cpiAddressList_Create(void);
+ * cpiAddressList_Destroy(&list);
+ * }
+ * @endcode
+ *
+ * @see cpiAddressList_Create
+ */
+void cpiAddressList_Destroy(CPIAddressList **addressListPtr);
+
+/**
+ * Appends the address, taking ownership of the memory
+ *
+ * @param list A pointer to a CPIAddressList.
+ * @param address must be non-null
+ * @return The input list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIAddressList *cpiAddressList_Append(CPIAddressList *list, CPIAddress *address);
+
+/**
+ * Creates a reference counted copy
+ *
+ * @param list A pointer to a valid {@link CPIAddressList}.
+ *
+ * @return An allocated list, you must destroy it.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIAddressList *cpiAddressList_Copy(const CPIAddressList *list);
+
+/**
+ * Determine if two CPIAddressList instances are equal.
+ *
+ * Two CPIAddressList instances are equal if, and only if, they have the same length,
+ * with the same elements in the same order.
+ *
+ *
+ * The following equivalence relations on non-null `CPIAddressList` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `CPIAddressList_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `CPIAddressList_Equals(x, y)` must return true if and only if
+ * `cpiAddressList_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiAddressList_Equals(x, y)` returns true and
+ * `cpiAddressList_Equals(y, z)` returns true,
+ * then `cpiAddressList_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `cpiAddressList_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `cpiAddressList_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `CPIAddressList` instance.
+ * @param b A pointer to a `CPIAddressList` instance.
+ * @return true if the two `CPIAddressList` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIAddressList *a = cpiAddressList_Create();
+ * CPIAddressList *b = cpiAddressList_Create();
+ *
+ * if (cpiAddressList_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool cpiAddressList_Equals(const CPIAddressList *a, const CPIAddressList *b);
+
+/**
+ * Get the number of items in the list
+ *
+ * @param list A pointer to a {@link CPIAddressList}.
+ * @return The number of items in the list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t cpiAddressList_Length(const CPIAddressList *list);
+
+/**
+ * Returns a const reference to an item.
+ * Use CPIAddress_Copy if needed.
+ *
+ * Do not free or modify the returned value.
+ * Use CPIAddress_Copy if you need a mutable instance.
+ *
+ * @param list A pointer to a CPIAddressList.
+ * @param item A value less than the number of items in the given {@link CPIAddressList}.
+ * @return Asserts if item off end of list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const CPIAddress *cpiAddressList_GetItem(const CPIAddressList *list, size_t item);
+
+/**
+ * Returns a JSON array of the addresses
+ *
+ * { "ADDRS" : [ {addr0}, {addr1}, ..., {addrN} ] }
+ *
+ * @param list A pointer to a CPIAddressList.
+ * @return A JSON object, even if array empty
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSONArray *cpiAddressList_ToJson(const CPIAddressList *list);
+
+/**
+ * Creates an address list based on a JSON array
+ *
+ * { "ADDRS" : [ {addr0}, {addr1}, ..., {addrN} ] }
+ *
+ * @param json A pointer to a valid PARCJSON instance.
+ * @return An allocated address list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIAddressList *cpiAddressList_CreateFromJson(PARCJSONArray *json);
+
+/**
+ * Get a nul-terminated, C-string representation of the given {@link CPIAddressList}.
+ *
+ * @param list A pointer to a valid {@link CPIAddressList} instance.
+ *
+ * @return An allocate string representation of the {@link CPIAddressList} that must be freed via `parcMemory_Deallocate()`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+char *cpiAddressList_ToString(const CPIAddressList *list);
+#endif // libccnx_cpi_AddressList_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_CancelFlow.c b/libccnx-transport-rta/ccnx/api/control/cpi_CancelFlow.c
new file mode 100644
index 00000000..4898282b
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_CancelFlow.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 <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/api/control/controlPlaneInterface.h>
+#include <ccnx/api/control/cpi_CancelFlow.h>
+#include <parc/algol/parc_Memory.h>
+
+static const char *cpiCancelFlow = "CPI_CANCEL_FLOW";
+static const char *cpiFlowName = "FLOW_NAME";
+
+PARCJSON *
+cpiCancelFlow_CreateRequest(const CCNxName *name)
+{
+ PARCJSON *operation = parcJSON_Create();
+
+ char *uri = ccnxName_ToString(name);
+ parcJSON_AddString(operation, cpiFlowName, uri);
+ parcMemory_Deallocate((void **) &uri);
+
+ PARCJSON *result = cpi_CreateRequest(cpiCancelFlow, operation);
+ parcJSON_Release(&operation);
+
+ return result;
+}
+
+PARCJSON *
+cpiCancelFlow_Create(const CCNxName *name)
+{
+ PARCJSON *operation = parcJSON_Create();
+
+ char *uri = ccnxName_ToString(name);
+ parcJSON_AddString(operation, cpiFlowName, uri);
+ parcMemory_Deallocate((void **) &uri);
+
+ PARCJSON *result = cpi_CreateRequest(cpiCancelFlow, operation);
+ parcJSON_Release(&operation);
+
+ return result;
+}
+
+CCNxName *
+cpiCancelFlow_GetFlowName(const PARCJSON *controlMessage)
+{
+ assertNotNull(controlMessage, "Parameter controlMessage must be non-null");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(controlMessage, cpiRequest_GetJsonTag());
+ assertNotNull(value, "only support getting the name from a Request at the moment, not from an ack/nack.");
+ PARCJSON *inner_json = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(inner_json, cpiCancelFlow_CancelFlowJsonTag());
+ assertNotNull(value, "Missing JSON tag in control message: %s", cpiCancelFlow_CancelFlowJsonTag());
+ inner_json = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(inner_json, cpiFlowName);
+ assertNotNull(value, "Missing JSON tag in control message: %s", cpiFlowName);
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ const char *uri = parcBuffer_Overlay(sBuf, 0);
+
+ CCNxName *name = ccnxName_CreateFromCString(uri);
+
+ return name;
+}
+
+CCNxName *
+cpiCancelFlow_NameFromControlMessage(CCNxControl *control)
+{
+ assertNotNull(control, "Parameter control must be non-null");
+ return cpiCancelFlow_GetFlowName(ccnxControl_GetJson(control));
+}
+
+bool
+cpiCancelFlow_SuccessFromResponse(CCNxControl *control)
+{
+ trapNotImplemented("cpiCancelFlow_SuccessFromResponse");
+}
+
+const char *
+cpiCancelFlow_CancelFlowJsonTag(void)
+{
+ return cpiCancelFlow;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_CancelFlow.h b/libccnx-transport-rta/ccnx/api/control/cpi_CancelFlow.h
new file mode 100644
index 00000000..77f846e5
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_CancelFlow.h
@@ -0,0 +1,108 @@
+/*
+ * 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 cpi_CancelFlow.h
+ * @brief Cancel a "flow"
+ *
+ */
+#ifndef libccnx_cpi_CancelFlow_h
+#define libccnx_cpi_CancelFlow_h
+
+#include <ccnx/api/control/cpi_ControlMessage.h>
+
+#include <ccnx/common/ccnx_Name.h>
+
+/**
+ * Creates a CPI reqeust to cancel a flow
+ *
+ * Will return an asynchronous ACK or NACK.
+ *
+ * @param name The CCNxName of the flow to cancel.
+ * @return A pointer to a valid CPIControlMessage
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *cpiCancelFlow_CreateRequest(const CCNxName *name);
+
+/**
+ * Creates a CPI reqeust to cancel a flow
+ *
+ * @param [in] name The CCNxName of the flow to cancel.
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a valid PARCJSON instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *cpiCancelFlow_Create(const CCNxName *name);
+
+/**
+ * Return the CCNxName associated with the given control message
+ *
+ * @param controlMessage A pointer to a control message.
+ * @return A pointer to a valid CCNxName instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxName *cpiCancelFlow_GetFlowName(const PARCJSON *controlMessage);
+
+/**
+ * Return the name associated with the message
+ *
+ * @param controlMessage A pointer to a control message.
+ * @return A pointer to a valid CCNxName instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxName *cpiCancelFlow_NameFromControlMessage(CCNxControl *controlMessage);
+
+/**
+ * Given a CPI response (ACK or NACK) return the success state
+ *
+ * @param controlMessage A pointer to a control message.
+ * @return true if the control message signals success.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool cpiCancelFlow_SuccessFromResponse(CCNxControl *controlMessage);
+
+/**
+ * The CPI tag used for cancel flow
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiCancelFlow_CancelFlowJsonTag(void);
+#endif // libccnx_cpi_CancelFlow_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Connection.c b/libccnx-transport-rta/ccnx/api/control/cpi_Connection.c
new file mode 100644
index 00000000..19ae8c1d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_Connection.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 <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_JSON.h>
+
+#include <ccnx/api/control/cpi_Connection.h>
+#include <ccnx/api/control/cpi_InterfaceGeneric.h>
+
+#define SOURCE_INDEX 0
+#define DESTINATION_INDEX 1
+
+const static char cpiIFIDX[] = "IFIDX";
+const static char cpiSRCADDR[] = "SRC";
+const static char cpiDSTADDR[] = "DST";
+const static char cpiCONNTYPE[] = "CONNTYPE";
+const static char cpiSTATE[] = "STATE";
+
+
+struct cpi_connection {
+ CPIInterfaceGeneric *generic;
+ CPIConnectionType tunnelType;
+};
+
+struct connection_type_string_s {
+ CPIConnectionType type;
+ const char *str;
+} connectionTypeStrings[] = {
+ { .type = cpiConnection_UDP, .str = "UDP" },
+ { .type = cpiConnection_TCP, .str = "TCP" },
+ { .type = cpiConnection_GRE, .str = "GRE" },
+ { .type = cpiConnection_MULTICAST, .str = "MCAST" },
+ { .type = cpiConnection_L2, .str = "L2" },
+ { .type = 0, .str = NULL },
+};
+
+
+static void
+_cpiConnection_Destroy(CPIConnection **iptunPtr)
+{
+ assertNotNull(iptunPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*iptunPtr, "Parameter must dereference to non-null pointer");
+
+ CPIConnection *iptun = *iptunPtr;
+ cpiInterfaceGeneric_Destroy(&iptun->generic);
+}
+
+parcObject_ExtendPARCObject(CPIConnection, _cpiConnection_Destroy, cpiConnection_Copy, cpiConnection_ToString, cpiConnection_Equals, NULL, NULL, cpiConnection_ToJson);
+
+parcObject_ImplementAcquire(cpiConnection, CPIConnection);
+
+parcObject_ImplementRelease(cpiConnection, CPIConnection);
+
+static PARCBufferComposer *
+cpiConnection_BuildString(const CPIConnection *connection, PARCBufferComposer *composer)
+{
+ cpiInterfaceGeneric_BuildString(connection->generic, composer);
+ cpiConnectionType_BuildString(connection->tunnelType, composer);
+
+ return composer;
+}
+
+char *
+cpiConnection_ToString(const CPIConnection *connection)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ cpiConnection_BuildString(connection, composer);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ return result;
+}
+
+PARCBufferComposer *
+cpiConnectionType_BuildString(CPIConnectionType type, PARCBufferComposer *composer)
+{
+ return parcBufferComposer_PutStrings(composer, " ", cpiConnectionType_ToString(type), NULL);
+}
+
+const char *
+cpiConnectionType_ToString(CPIConnectionType type)
+{
+ for (int i = 0; connectionTypeStrings[i].str != NULL; i++) {
+ if (connectionTypeStrings[i].type == type) {
+ return connectionTypeStrings[i].str;
+ }
+ }
+ trapIllegalValue(type, "Unknown type: %d", type);
+}
+
+CPIConnectionType
+cpiConnectionType_FromString(const char *str)
+{
+ for (int i = 0; connectionTypeStrings[i].str != NULL; i++) {
+ if (strcasecmp(connectionTypeStrings[i].str, str) == 0) {
+ return connectionTypeStrings[i].type;
+ }
+ }
+ trapIllegalValue(type, "Unknown type: %s", str);
+}
+
+CPIConnection *
+cpiConnection_Create(unsigned ifidx, CPIAddress *source, CPIAddress *destination, CPIConnectionType tunnelType)
+{
+ assertNotNull(source, "Parameter source must be non-null");
+ assertNotNull(destination, "Parameter destination must be non-null");
+
+ CPIConnection *iptun = parcObject_CreateInstance(CPIConnection);
+ assertNotNull(iptun, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIConnection));
+
+ CPIAddressList *addrlist = cpiAddressList_Create();
+ cpiAddressList_Append(addrlist, source);
+ cpiAddressList_Append(addrlist, destination);
+
+ iptun->generic = cpiInterfaceGeneric_Create(ifidx, addrlist);
+ iptun->tunnelType = tunnelType;
+ return iptun;
+}
+
+CPIConnection *
+cpiConnection_Copy(const CPIConnection *original)
+{
+ assertNotNull(original, "Parameter original must be non-null");
+ CPIConnection *iptun = parcObject_CreateInstance(CPIConnection);
+ assertNotNull(iptun, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIConnection));
+ iptun->generic = cpiInterfaceGeneric_Copy(original->generic);
+ iptun->tunnelType = original->tunnelType;
+ return iptun;
+}
+
+void
+cpiConnection_SetState(CPIConnection *iptun, CPIInterfaceStateType state)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+ cpiInterfaceGeneric_SetState(iptun->generic, state);
+}
+
+unsigned
+cpiConnection_GetIndex(const CPIConnection *iptun)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+ return cpiInterfaceGeneric_GetIndex(iptun->generic);
+}
+
+const CPIAddress *
+cpiConnection_GetSourceAddress(const CPIConnection *iptun)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+ const CPIAddressList *addrs = cpiInterfaceGeneric_GetAddresses(iptun->generic);
+ return cpiAddressList_GetItem(addrs, SOURCE_INDEX);
+}
+
+const CPIAddress *
+cpiConnection_GetDestinationAddress(const CPIConnection *iptun)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+ const CPIAddressList *addrs = cpiInterfaceGeneric_GetAddresses(iptun->generic);
+ return cpiAddressList_GetItem(addrs, DESTINATION_INDEX);
+}
+
+CPIConnectionType
+cpiConnection_GetConnectionType(const CPIConnection *iptun)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+ return iptun->tunnelType;
+}
+
+CPIInterfaceStateType
+cpiConnection_GetState(const CPIConnection *iptun)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+ return cpiInterfaceGeneric_GetState(iptun->generic);
+}
+
+bool
+cpiConnection_Equals(const CPIConnection *a, const CPIConnection *b)
+{
+ assertNotNull(a, "Parameter a must be non-null");
+ assertNotNull(b, "Parameter b must be non-null");
+
+ if (a->tunnelType == b->tunnelType) {
+ return cpiInterfaceGeneric_Equals(a->generic, b->generic);
+ }
+ return false;
+}
+
+static const char *cpiConnection = "Connection";
+
+PARCJSON *
+cpiConnection_ToJson(const CPIConnection *iptun)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+
+ PARCJSON *inner_json = parcJSON_Create();
+
+ parcJSON_AddInteger(inner_json, cpiIFIDX, cpiConnection_GetIndex(iptun));
+
+ if (cpiConnection_GetState(iptun) != CPI_IFACE_UNKNOWN) {
+ parcJSON_AddString(inner_json, cpiSTATE, cpiInterfaceStateType_ToString(cpiConnection_GetState(iptun)));
+ }
+
+ parcJSON_AddString(inner_json, cpiCONNTYPE, cpiConnectionType_ToString(cpiConnection_GetConnectionType(iptun)));
+
+ PARCJSON *json = cpiAddress_ToJson(cpiConnection_GetSourceAddress(iptun));
+ parcJSON_AddObject(inner_json, cpiSRCADDR, json);
+ parcJSON_Release(&json);
+
+ json = cpiAddress_ToJson(cpiConnection_GetDestinationAddress(iptun));
+ parcJSON_AddObject(inner_json, cpiDSTADDR, json);
+ parcJSON_Release(&json);
+
+ PARCJSON *outter_json = parcJSON_Create();
+ parcJSON_AddObject(outter_json, cpiConnection, inner_json);
+ parcJSON_Release(&inner_json);
+
+ return outter_json;
+}
+
+CPIConnection *
+cpiConnection_CreateFromJson(PARCJSON *json)
+{
+ assertNotNull(json, "Parameter must be non-null");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpiConnection);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpiConnection,
+ parcJSON_ToString(json));
+
+ PARCJSON *connectionJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(connectionJson, cpiIFIDX);
+ assertNotNull(value,
+ "Could not find key %s: %s", cpiIFIDX, parcJSON_ToString(json));
+ assertTrue(parcJSONValue_IsNumber(value),
+ "%s is not a number: %s",
+ cpiIFIDX,
+ parcJSON_ToString(json));
+ PARCJSONValue *ifidx_value = value;
+
+ value = parcJSON_GetValueByName(connectionJson, cpiCONNTYPE);
+ assertNotNull(value,
+ "Could not find key %s: %s", cpiCONNTYPE, parcJSON_ToString(json));
+ assertTrue(parcJSONValue_IsString(value),
+ "%s is not a number: %s",
+ cpiCONNTYPE,
+ parcJSON_ToString(json));
+ PARCJSONValue *tuntype_value = value;
+
+ value = parcJSON_GetValueByName(connectionJson, cpiSRCADDR);
+ assertNotNull(value,
+ "Could not find key %s: %s", cpiSRCADDR, parcJSON_ToString(json));
+ assertTrue(parcJSONValue_IsJSON(value),
+ "%s is not an array: %s",
+ cpiSRCADDR,
+ parcJSON_ToString(json));
+ PARCJSONValue *srcaddr_value = value;
+
+ value = parcJSON_GetValueByName(connectionJson, cpiDSTADDR);
+ assertNotNull(value,
+ "Could not find key %s: %s", cpiDSTADDR, parcJSON_ToString(json));
+ PARCJSONValue *dstaddr_value = value;
+ assertTrue(parcJSONValue_IsJSON(value),
+ "%s is not an array: %s",
+ cpiDSTADDR,
+ parcJSON_ToString(json));
+
+ unsigned ifidx = (unsigned) parcJSONValue_GetInteger(ifidx_value);
+ CPIAddress *srcaddr =
+ cpiAddress_CreateFromJson(parcJSONValue_GetJSON(srcaddr_value));
+ CPIAddress *dstaddr =
+ cpiAddress_CreateFromJson(parcJSONValue_GetJSON(dstaddr_value));
+ PARCBuffer *sbuf = parcJSONValue_GetString(tuntype_value);
+ CPIConnectionType tunnelType =
+ cpiConnectionType_FromString(parcBuffer_Overlay(sbuf, 0));
+
+ CPIConnection *iptun = cpiConnection_Create(ifidx, srcaddr, dstaddr, tunnelType);
+
+ PARCJSONValue *state_value = parcJSON_GetValueByName(connectionJson, cpiSTATE);
+ if (state_value != NULL) {
+ sbuf = parcJSONValue_GetString(state_value);
+ cpiConnection_SetState(iptun, cpiInterfaceStateType_FromString(parcBuffer_Overlay(sbuf, 0)));
+ }
+
+ return iptun;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Connection.h b/libccnx-transport-rta/ccnx/api/control/cpi_Connection.h
new file mode 100644
index 00000000..dea866e8
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_Connection.h
@@ -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.
+ */
+
+/**
+ * @file cpi_Connection.h
+ * @brief Represents a point-to-point tunnel over IP.
+ *
+ * The carries can be UDP, TCP, or GRE
+ *
+ * We use InterfaceGeneric to back this type. We always use 2 addresses in the address list.
+ * Address 0 is the source and address 1 is the destination.
+ *
+ */
+#ifndef libccnx_cpi_Connection_h
+#define libccnx_cpi_Connection_h
+
+#include <ccnx/api/control/cpi_InterfaceType.h>
+#include <ccnx/api/control/cpi_Address.h>
+
+struct cpi_connection;
+typedef struct cpi_connection CPIConnection;
+
+typedef enum {
+ cpiConnection_GRE,
+ cpiConnection_TCP,
+ cpiConnection_UDP,
+ cpiConnection_MULTICAST,
+ cpiConnection_L2
+} CPIConnectionType;
+
+/**
+ * Return a static, nul-terminated C string representing the given `CPIConnectionType`
+ *
+ * @param type A valid CPIConnectionType value.
+ * @return A static, nul-terminated C string
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiConnectionType_ToString(CPIConnectionType type);
+
+/**
+ * <#OneLineDescription#>
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIConnectionType cpiConnectionType_FromString(const char *typeAsString);
+
+/**
+ * <#OneLineDescription#>
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *cpiConnectionType_BuildString(CPIConnectionType type, PARCBufferComposer *composer);
+
+/**
+ * A representation of a Connection, being two addresses and a type
+ *
+ * <#Discussion#>
+ *
+ * @param ifidx The interface index
+ * @param source is the local address
+ * @param destination is the remote address
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIConnection *cpiConnection_Create(unsigned ifidx, CPIAddress *source, CPIAddress *destination, CPIConnectionType connType);
+
+
+CPIConnection *cpiConnection_Acquire(const CPIConnection *conn);
+
+/**
+ * Creates a reference counted copy
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return An allocated copy, you must destroy it
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIConnection *cpiConnection_Copy(const CPIConnection *conn);
+
+/**
+ * Reference counted release
+ *
+ * Only on the last reference will the call free the contents.
+ *
+ * @param <#param1#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void cpiConnection_Release(CPIConnection **connPtr);
+
+/**
+ * A connection may be up, down, or don't know state.
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void cpiConnection_SetState(CPIConnection *conn, CPIInterfaceStateType state);
+
+/**
+ * Returns the interface index
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return The interface index
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+unsigned cpiConnection_GetIndex(const CPIConnection *conn);
+
+/**
+ * The source address
+ *
+ * This is not a copy, it is the pointer to what is in the object. If you
+ * want to save it, make a copy.
+ *
+ * @param <#param1#>
+ * @return Do not destroy it.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const CPIAddress *cpiConnection_GetSourceAddress(const CPIConnection *conn);
+
+/**
+ * The destination (remote) address
+ *
+ * This is not a copy, it is the pointer to what is in the object. If you
+ * want to save it, make a copy.
+ *
+ * @param <#param1#>
+ * @return Do not destroy it.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const CPIAddress *cpiConnection_GetDestinationAddress(const CPIConnection *conn);
+
+/**
+ * The type of connection
+ *
+ * A connection may be a TCP tunnel, UDP tunnel, IP multicast overlay,
+ * PF_LOCAL connection, or a layer 2 connection.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIConnectionType cpiConnection_GetConnectionType(const CPIConnection *conn);
+
+/**
+ * The connection state, Up, Down, or Don't Know
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIInterfaceStateType cpiConnection_GetState(const CPIConnection *conn);
+
+/**
+ * Determine if two CPIConnection instances are equal.
+ *
+ * Two CPIConnection instances are equal if, and only if,
+ * (a) the interface index is the same, (b) the connection types are the same,
+ * (c) the connection state is the same, (d) the source address are the same, and
+ * (e) the destination addresses are the same.
+ *
+ * The following equivalence relations on non-null `CPIConnection` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `CPIConnection_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `cpiConnection_Equals(x, y)` must return true if and only if
+ * `cpiConnection_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiConnection_Equals(x, y)` returns true and
+ * `cpiConnection_Equals(y, z)` returns true,
+ * then `cpiConnection_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `cpiConnection_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `cpiConnection_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `CPIConnection` instance.
+ * @param b A pointer to a `CPIConnection` instance.
+ * @return true if the two `CPIConnection` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIConnection *a = cpiConnection_Create();
+ * CPIConnection *b = cpiConnection_Create();
+ *
+ * if (cpiConnection_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool cpiConnection_Equals(const CPIConnection *a, const CPIConnection *b);
+
+/**
+ * A JSON representation of the connection
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return An allocated object that you must destroy
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *cpiConnection_ToJson(const CPIConnection *conn);
+
+/**
+ * Creates a Connection object based on a JSON representation.
+ *
+ * Will assert if there's a parsing error
+ *
+ * @param <#param1#>
+ * @return An allocated connection that you must destroy
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIConnection *cpiConnection_CreateFromJson(PARCJSON *json);
+
+/**
+ * <#OneLineDescription#>
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+char *cpiConnection_ToString(const CPIConnection *connection);
+#endif // libccnx_cpi_Connection_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ConnectionEthernet.c b/libccnx-transport-rta/ccnx/api/control/cpi_ConnectionEthernet.c
new file mode 100644
index 00000000..be4793fe
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ConnectionEthernet.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 <LongBow/runtime.h>
+
+#include <ccnx/api/control/cpi_ConnectionEthernet.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_JSON.h>
+
+#include <ccnx/api/control/controlPlaneInterface.h>
+extern uint64_t cpi_GetNextSequenceNumber(void);
+
+// JSON keys
+static const char *KEY_IFNAME = "IFNAME";
+static const char *KEY_ADDR = "PEER_ADDR";
+static const char *KEY_ETHERTYPE = "ETHERTYPE";
+static const char *KEY_SYMBOLIC = "SYMBOLIC";
+
+static const char *KEY_ADDETHER = "AddConnEther";
+static const char *KEY_REMOVEETHER = "RemoveConnEther";
+
+struct cpi_connection_ethernet {
+ char *interfaceName;
+ char *symbolic;
+ CPIAddress *peerLinkAddress;
+ uint16_t ethertype;
+};
+
+CPIConnectionEthernet *
+cpiConnectionEthernet_Create(const char *interfaceName, CPIAddress *peerLinkAddress, uint16_t ethertype, const char *symbolic)
+{
+ assertNotNull(interfaceName, "Parameter interfaceName must be non-null");
+ assertNotNull(peerLinkAddress, "Parameter peerLinkAddress must be non-null");
+
+ CPIConnectionEthernet *etherConn = parcMemory_AllocateAndClear(sizeof(CPIConnectionEthernet));
+ if (etherConn) {
+ etherConn->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName));
+ etherConn->symbolic = parcMemory_StringDuplicate(symbolic, strlen(symbolic));
+ etherConn->peerLinkAddress = cpiAddress_Copy(peerLinkAddress);
+ etherConn->ethertype = ethertype;
+ }
+
+ return etherConn;
+}
+
+void
+cpiConnectionEthernet_Release(CPIConnectionEthernet **etherConnPtr)
+{
+ assertNotNull(etherConnPtr, "Parameter etherConnPtr must be non-null double pointer");
+ assertNotNull(*etherConnPtr, "Parameter etherConnPtr dereference to non-null pointer");
+
+ CPIConnectionEthernet *etherConn = *etherConnPtr;
+ cpiAddress_Destroy(&etherConn->peerLinkAddress);
+ parcMemory_Deallocate((void **) &(etherConn->interfaceName));
+ parcMemory_Deallocate((void **) &(etherConn->symbolic));
+ parcMemory_Deallocate((void **) &etherConn);
+ *etherConnPtr = NULL;
+}
+
+bool
+cpiConnectionEthernet_Equals(const CPIConnectionEthernet *a, const CPIConnectionEthernet *b)
+{
+ if ((a == NULL && b == NULL) || a == b) {
+ // both null or identically equal
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ // only one is null
+ return false;
+ }
+
+ if (a->ethertype == b->ethertype) {
+ if (cpiAddress_Equals(a->peerLinkAddress, b->peerLinkAddress)) {
+ if (strcmp(a->interfaceName, b->interfaceName) == 0) {
+ if (strcmp(a->symbolic, b->symbolic) == 0) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+static PARCJSON *
+_cpiConnectionEthernet_ToJson(const CPIConnectionEthernet *etherConn)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ // ------ Interface Name
+ parcJSON_AddString(json, KEY_IFNAME, etherConn->interfaceName);
+
+ // ------ Symbolic Name
+ parcJSON_AddString(json, KEY_SYMBOLIC, etherConn->symbolic);
+
+ // ------ Link Address
+ PARCJSON *peerLinkJson = cpiAddress_ToJson(etherConn->peerLinkAddress);
+ parcJSON_AddObject(json, KEY_ADDR, peerLinkJson);
+ parcJSON_Release(&peerLinkJson);
+
+ // ------ EtherType
+ parcJSON_AddInteger(json, KEY_ETHERTYPE, etherConn->ethertype);
+
+ return json;
+}
+
+/*
+ * We want to create a JSON object that looks like this
+ * {
+ * "CPI_REQUEST" :
+ * { "SEQUENCE" : <sequence number>,
+ * <operationName> : { "IFNAME" : "em1", "SYMBOLIC" : "conn0", "PEER_ADDR" : { "ADDRESSTYPE" : "LINK", "DATA" : "AQIDBAUG" }, "ETHERTYPE" : 2049 },
+ * }
+ * }
+ */
+static CCNxControl *
+_cpiConnectionEthernet_CreateControlMessage(const CPIConnectionEthernet *etherConn, const char *operationName)
+{
+ PARCJSON *cpiRequest = parcJSON_Create();
+
+ // --- add the seqnum
+
+ uint64_t seqnum = cpi_GetNextSequenceNumber();
+ parcJSON_AddInteger(cpiRequest, "SEQUENCE", (int) seqnum);
+
+ // -- Add the operation
+ PARCJSON *operation = _cpiConnectionEthernet_ToJson(etherConn);
+ parcJSON_AddObject(cpiRequest, operationName, operation);
+ parcJSON_Release(&operation);
+
+ // -- Do the final encapusulation
+ PARCJSON *final = parcJSON_Create();
+ parcJSON_AddObject(final, cpiRequest_GetJsonTag(), cpiRequest);
+ parcJSON_Release(&cpiRequest);
+
+ // -- Create the CPIControlMessage
+ char *finalString = parcJSON_ToCompactString(final);
+
+ parcJSON_Release(&final);
+
+ PARCJSON *oldJson = parcJSON_ParseString(finalString);
+ CCNxControl *result = ccnxControl_CreateCPIRequest(oldJson);
+ parcJSON_Release(&oldJson);
+
+ parcMemory_Deallocate((void **) &finalString);
+
+ return result;
+}
+
+CCNxControl *
+cpiConnectionEthernet_CreateAddMessage(const CPIConnectionEthernet *etherConn)
+{
+ assertNotNull(etherConn, "Parameter etherConn must be non-null");
+ CCNxControl *control = _cpiConnectionEthernet_CreateControlMessage(etherConn, KEY_ADDETHER);
+ return control;
+}
+
+CCNxControl *
+cpiConnectionEthernet_CreateRemoveMessage(const CPIConnectionEthernet *etherConn)
+{
+ assertNotNull(etherConn, "Parameter etherConn must be non-null");
+ CCNxControl *control = _cpiConnectionEthernet_CreateControlMessage(etherConn, KEY_REMOVEETHER);
+ return control;
+}
+
+static bool
+_cpiConnectionEthernet_IsMessageType(const CCNxControl *control, const char *operationName)
+{
+ bool isOperation = false;
+ if (ccnxControl_IsCPI(control)) {
+ PARCJSON *oldJson = ccnxControl_GetJson(control);
+ PARCJSONValue *value = parcJSON_GetValueByName(oldJson, cpiRequest_GetJsonTag());
+
+ if (value != NULL) {
+ PARCJSON *innerJson = parcJSONValue_GetJSON(value);
+ // the second array element is the key we're looking for
+ PARCJSONPair *pair = parcJSON_GetPairByIndex(innerJson, 1);
+ if (pair != NULL) {
+ const char *opKey = parcBuffer_Overlay(parcJSONPair_GetName(pair), 0);
+ if (opKey && strcasecmp(opKey, operationName) == 0) {
+ isOperation = true;
+ }
+ }
+ }
+ }
+
+ return isOperation;
+}
+
+bool
+cpiConnectionEthernet_IsAddMessage(const CCNxControl *control)
+{
+ assertNotNull(control, "Parameter control must be non-null");
+ return _cpiConnectionEthernet_IsMessageType(control, KEY_ADDETHER);
+}
+
+bool
+cpiConnectionEthernet_IsRemoveMessage(const CCNxControl *control)
+{
+ assertNotNull(control, "Parameter control must be non-null");
+ return _cpiConnectionEthernet_IsMessageType(control, KEY_REMOVEETHER);
+}
+
+CPIConnectionEthernet *
+cpiConnectionEthernet_FromControl(const CCNxControl *control)
+{
+ assertNotNull(control, "Parameter control must be non-null");
+
+ CPIConnectionEthernet *etherConn = NULL;
+
+ if (ccnxControl_IsCPI(control)) {
+ PARCJSON *oldJson = ccnxControl_GetJson(control);
+ PARCJSONValue *value = parcJSON_GetValueByName(oldJson, cpiRequest_GetJsonTag());
+
+ if (value != NULL) {
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Wrong JSON type for %s, expected JSON: %s",
+ cpiRequest_GetJsonTag(), parcJSON_ToString(oldJson));
+ PARCJSON *requestJson = parcJSONValue_GetJSON(value);
+ // the second array element is the key we're looking for
+ PARCJSONPair *pair = parcJSON_GetPairByIndex(requestJson, 1);
+ const char *opKey = parcBuffer_Overlay(parcJSONPair_GetName(pair), 0);
+ if (opKey && ((strcasecmp(opKey, KEY_ADDETHER) == 0) || strcasecmp(opKey, KEY_REMOVEETHER))) {
+ PARCJSON *opJson = parcJSONValue_GetJSON(parcJSONPair_GetValue(pair));
+
+ // Ok, it is one of our messages, now assemble the pieces
+ value = parcJSON_GetValueByName(opJson, KEY_IFNAME);
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ const char *ifname = parcBuffer_Overlay(sBuf, 0);
+ value = parcJSON_GetValueByName(opJson, KEY_SYMBOLIC);
+ sBuf = parcJSONValue_GetString(value);
+ const char *symbolic = parcBuffer_Overlay(sBuf, 0);
+ value = parcJSON_GetValueByName(opJson, KEY_ETHERTYPE);
+ int ethertype = (int) parcJSONValue_GetInteger(value);
+ value = parcJSON_GetValueByName(opJson, KEY_ADDR);
+ PARCJSON *addrJson = parcJSONValue_GetJSON(value);
+ assertNotNull(addrJson, "JSON missing the key %s", KEY_ADDR);
+
+ CPIAddress *peerAddress = cpiAddress_CreateFromJson(addrJson);
+ assertNotNull(peerAddress, "Failed to decode the peer address from %s", parcJSON_ToString(addrJson));
+
+ etherConn = cpiConnectionEthernet_Create(ifname, peerAddress, (uint16_t) ethertype, symbolic);
+
+ cpiAddress_Destroy(&peerAddress);
+ }
+ }
+ }
+
+ return etherConn;
+}
+
+const char *
+cpiConnectionEthernet_GetInterfaceName(const CPIConnectionEthernet *etherConn)
+{
+ assertNotNull(etherConn, "Parameter etherConn must be non-null");
+ return etherConn->interfaceName;
+}
+
+const char *
+cpiConnectionEthernet_GetSymbolicName(const CPIConnectionEthernet *etherConn)
+{
+ assertNotNull(etherConn, "Parameter etherConn must be non-null");
+ return etherConn->symbolic;
+}
+
+CPIAddress *
+cpiConnectionEthernet_GetPeerLinkAddress(const CPIConnectionEthernet *etherConn)
+{
+ assertNotNull(etherConn, "Parameter etherConn must be non-null");
+ return etherConn->peerLinkAddress;
+}
+
+uint16_t
+cpiConnectionEthernet_GetEthertype(const CPIConnectionEthernet *etherConn)
+{
+ assertNotNull(etherConn, "Parameter etherConn must be non-null");
+ return etherConn->ethertype;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ConnectionEthernet.h b/libccnx-transport-rta/ccnx/api/control/cpi_ConnectionEthernet.h
new file mode 100644
index 00000000..877810b2
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ConnectionEthernet.h
@@ -0,0 +1,281 @@
+/*
+ * 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 cpi_ConnectionEthernet.h
+ * @brief Represents an ethernet connection
+ *
+ * An ethernet connection is a (local interface name, remote mac address, ethertype) tuple. A unicast
+ * connection, for example, could be ("em3", 3c:15:c2:e7:c5:ca, 0x0801). The broadcast connection would
+ * be ("em3", ff:ff:ff:ff:ff:ff, 0x0801). You could also use group mac addresses.
+ *
+ * Creating an ethernet connetion in the forwarder sets up an entry in the connection table that
+ * you an then attach routes to. For example, you could add a route to /foo via the connection
+ * ("em3", 3c:15:c2:e7:c5:ca, 0x0801), in which case an Interest would be unicast that way. A route
+ * to a broadcast or group address would broadcast the interest.
+ *
+ */
+
+#ifndef CCNx_Control_API_cpi_ConnectionEthernet_h
+#define CCNx_Control_API_cpi_ConnectionEthernet_h
+
+struct cpi_connection_ethernet;
+typedef struct cpi_connection_ethernet CPIConnectionEthernet;
+
+#include <ccnx/api/control/cpi_Address.h>
+#include <ccnx/api/control/cpi_ControlMessage.h>
+
+/**
+ * Creates a CPIConnectionEthernet object
+ *
+ * The symbolic name represents this connection and may be used by other commands. It must be
+ * unique, otherwise the command will fail when sent to the forwarder.
+ *
+ * @param [in] interfaceName The name of the local interface
+ * @param [in] peerLinkAddress The link layer address of the peer (stores a reference to it)
+ * @param [in] ethertype The ethertype to use (host byte order)
+ * @param [in] symbolic The user-defined symbolic name
+ *
+ * @return non-null An Allocated object
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIConnectionEthernet *cpiConnectionEthernet_Create(const char *interfaceName, CPIAddress *peerLinkAddress, uint16_t ethertype, const char *symbolic);
+
+/**
+ * Releases a reference count to the object
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in,out] etherConnPtr A pointer to an etherConn object, will be null'd.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void cpiConnectionEthernet_Release(CPIConnectionEthernet **etherConnPtr);
+
+/**
+ * Determine if two CPIConnectionEthernet instances are equal.
+ *
+ * Two CPIConnectionEthernet instances are equal if, and only if,
+ * they are either both null or both non-null and compare
+ * as equal field-for-field over (interfaceName, peerLinkAddress, ethertype, symbolic).
+ *
+ * The interface name is case sensitive, so "ETH0" is not the same as "eth0".
+ *
+ *
+ * The following equivalence relations on non-null `CPIConnectionEthernet` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `CPIConnectionEthernet_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `cpiConnectionEthernet_Equals(x, y)` must return true if and only if
+ * `cpiConnectionEthernet_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiConnectionEthernet_Equals(x, y)` returns true and
+ * `cpiConnectionEthernet_Equals(y, z)` returns true,
+ * then `cpiConnectionEthernet_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `cpiConnectionEthernet_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `cpiConnectionEthernet_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `CPIConnectionEthernet` instance.
+ * @param b A pointer to a `CPIConnectionEthernet` instance.
+ * @return true if the two `CPIConnectionEthernet` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIConnectionEthernet *a = cpiConnectionEthernet_Create();
+ * CPIConnectionEthernet *b = cpiConnectionEthernet_Create();
+ *
+ * if (cpiConnectionEthernet_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+
+bool cpiConnectionEthernet_Equals(const CPIConnectionEthernet *a, const CPIConnectionEthernet *b);
+
+/**
+ * Creates a control message to add the connection
+ *
+ * An add message indicates to the forwarder that it should add the corresponding
+ * Ethernet connection.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null a CPI control message
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxControl *cpiConnectionEthernet_CreateAddMessage(const CPIConnectionEthernet *etherConn);
+
+/**
+ * Creates a control message to remove the connection
+ *
+ * A remove message indicates to the forwarder that it should remove the corresponding
+ * Ethernet connection.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null a CPI control message
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxControl *cpiConnectionEthernet_CreateRemoveMessage(const CPIConnectionEthernet *etherConn);
+
+/**
+ * Checks if the control message is an Add command
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return true Message is an Add command for a ConnectionEthernet
+ * @return false Message is not an Add command for a ConnectionEthernet
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool cpiConnectionEthernet_IsAddMessage(const CCNxControl *control);
+
+/**
+ * Checks if the message is a Remove command
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] control A CCNx Control message
+ *
+ * @return true Message is an Remove command for a ConnectionEthernet
+ * @return false Message is not Remove Add command for a ConnectionEthernet
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool cpiConnectionEthernet_IsRemoveMessage(const CCNxControl *control);
+
+/**
+ * Creates an object from the control message
+ *
+ * The object does not carry any sense of Add or Remove, that is only part of the
+ * Control message.
+ *
+ * @param [in] control A CCNx Control message
+ *
+ * @return non-null An Allocated object
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIConnectionEthernet *cpiConnectionEthernet_FromControl(const CCNxControl *control);
+
+/**
+ * Returns the interface name
+ *
+ * The caller should duplicate the string if it will be stored.
+ *
+ * @param [in] etherConn An allocated CPIConnectionEthernet
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiConnectionEthernet_GetInterfaceName(const CPIConnectionEthernet *etherConn);
+
+/**
+ * Returns the symbolic name
+ *
+ * The caller should duplicate the string if it will be stored.
+ *
+ * @param [in] etherConn An allocated CPIConnectionEthernet
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiConnectionEthernet_GetSymbolicName(const CPIConnectionEthernet *etherConn);
+
+/**
+ * Returns the peer link address
+ *
+ * Returns the peer's link address (e.g. 48-bit MAC address). The caller should
+ * acquire its own reference if he address will be stored externally to the
+ * CPIConnectionEthernet.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null The peer's link address
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIAddress *cpiConnectionEthernet_GetPeerLinkAddress(const CPIConnectionEthernet *etherConn);
+
+/**
+ * Returns the ethertype to use
+ *
+ * The ethertype will be in host byte order.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint16_t cpiConnectionEthernet_GetEthertype(const CPIConnectionEthernet *etherConn);
+#endif // CCNx_Control_API_cpi_ConnectionEthernet_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ConnectionList.c b/libccnx-transport-rta/ccnx/api/control/cpi_ConnectionList.c
new file mode 100644
index 00000000..c4969fe9
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ConnectionList.c
@@ -0,0 +1,160 @@
+/*
+ * 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_ArrayList.h>
+
+#include <ccnx/api/control/cpi_ConnectionList.h>
+#include <LongBow/runtime.h>
+
+struct cpi_connection_list {
+ PARCArrayList *listOfConnections;
+};
+
+/**
+ * PARCArrayList entry destroyer
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+_cpiConnectionList_ArrayDestroyer(void **voidPtr)
+{
+ CPIConnection **entryPtr = (CPIConnection **) voidPtr;
+ cpiConnection_Release(entryPtr);
+}
+
+CPIConnectionList *
+cpiConnectionList_Create()
+{
+ CPIConnectionList *list = parcMemory_AllocateAndClear(sizeof(CPIConnectionList));
+ assertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIConnectionList));
+ list->listOfConnections = parcArrayList_Create(_cpiConnectionList_ArrayDestroyer);
+ return list;
+}
+
+void
+cpiConnectionList_Destroy(CPIConnectionList **listPtr)
+{
+ assertNotNull(listPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*listPtr, "Parameter must dereference to non-null pointer");
+ CPIConnectionList *list = *listPtr;
+ parcArrayList_Destroy(&list->listOfConnections);
+ parcMemory_Deallocate((void **) &list);
+ *listPtr = NULL;
+}
+
+void
+cpiConnectionList_Append(CPIConnectionList *list, CPIConnection *entry)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ assertNotNull(entry, "Parameter entry must be non-null");
+
+ parcArrayList_Add(list->listOfConnections, entry);
+}
+
+size_t
+cpiConnectionList_Length(const CPIConnectionList *list)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ return parcArrayList_Size(list->listOfConnections);
+}
+
+CPIConnection *
+cpiConnectionList_Get(CPIConnectionList *list, size_t index)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ CPIConnection *original = (CPIConnection *) parcArrayList_Get(list->listOfConnections, index);
+ return cpiConnection_Copy(original);
+}
+
+bool
+cpiConnectionList_Equals(const CPIConnectionList *a, const CPIConnectionList *b)
+{
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (parcArrayList_Size(a->listOfConnections) == parcArrayList_Size(b->listOfConnections)) {
+ size_t length = parcArrayList_Size(a->listOfConnections);
+ for (size_t i = 0; i < length; i++) {
+ CPIConnection *tunnel_a = (CPIConnection *) parcArrayList_Get(a->listOfConnections, i);
+ CPIConnection *tunnel_b = (CPIConnection *) parcArrayList_Get(b->listOfConnections, i);
+ if (!cpiConnection_Equals(tunnel_a, tunnel_b)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+const char cpi_ConnectionList[] = "ConnectionList";
+
+PARCJSON *
+cpiConnectionList_ToJson(const CPIConnectionList *list)
+{
+ assertNotNull(list, "Parameter must be non-null");
+
+ PARCJSONArray *inner_json = parcJSONArray_Create();
+
+ size_t length = parcArrayList_Size(list->listOfConnections);
+ for (size_t i = 0; i < length; i++) {
+ CPIConnection *tunnel = (CPIConnection *) parcArrayList_Get(list->listOfConnections, i);
+ PARCJSON *json = cpiConnection_ToJson(tunnel);
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ parcJSON_Release(&json);
+ parcJSONArray_AddValue(inner_json, value);
+ parcJSONValue_Release(&value);
+ }
+
+ PARCJSON *outter_json = parcJSON_Create();
+ parcJSON_AddArray(outter_json, cpi_ConnectionList, inner_json);
+ parcJSONArray_Release(&inner_json);
+ return outter_json;
+}
+
+CPIConnectionList *
+cpiConnectionList_FromJson(PARCJSON *json)
+{
+ assertNotNull(json, "Parameter must be non-null");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpi_ConnectionList);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpi_ConnectionList,
+ parcJSON_ToString(json));
+ PARCJSONArray *tunnelListJson = parcJSONValue_GetArray(value);
+
+ CPIConnectionList *list = cpiConnectionList_Create();
+
+ size_t length = parcJSONArray_GetLength(tunnelListJson);
+ for (size_t i = 0; i < length; i++) {
+ value = parcJSONArray_GetValue(tunnelListJson, i);
+ PARCJSON *tunnelJson = parcJSONValue_GetJSON(value);
+ CPIConnection *tunnel = cpiConnection_CreateFromJson(tunnelJson);
+ cpiConnectionList_Append(list, tunnel);
+ }
+
+ return list;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ConnectionList.h b/libccnx-transport-rta/ccnx/api/control/cpi_ConnectionList.h
new file mode 100644
index 00000000..6fdd4e64
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ConnectionList.h
@@ -0,0 +1,185 @@
+/*
+ * 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 cpi_ConnectionList.h
+ * @brief A list of CPIConnection objects
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_cpi_ConnectionList_h
+#define libccnx_cpi_ConnectionList_h
+
+struct cpi_connection_list;
+typedef struct cpi_connection_list CPIConnectionList;
+
+#include <ccnx/api/control/cpi_Connection.h>
+
+/**
+ * Creates an empty list of CPIConnection objects
+ *
+ * Each element in the list is reference counted, so the list may persist beyond
+ * what created it.
+ *
+ * @param <#param1#>
+ * @return An allocated list, you must call <code>cpiConnectionList_Destroy()</code>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIConnectionList *cpiConnectionList_Create(void);
+
+/**
+ * Destroys the list and all references in it
+ *
+ * Destroys each element in the list, which are reference counted. Only
+ * on the last destroy of each element is it actually freed.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void cpiConnectionList_Destroy(CPIConnectionList **listPtr);
+
+/**
+ * Adds a iptunnel entry to the list.
+ *
+ * Appends <code>entry</code> to the list. Takes ownership of the entry
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void cpiConnectionList_Append(CPIConnectionList *list, CPIConnection *entry);
+
+/**
+ * Determine if two CPIConnectionList instances are equal.
+ *
+ * Two CPIConnectionList instances are equal if, and only if,they have the same number of objects and
+ * the objects -- in order -- are equal.
+ *
+ * The following equivalence relations on non-null `CPIConnectionList` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `CPIConnectionList_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `cpiConnectionList_Equals(x, y)` must return true if and only if
+ * `cpiConnectionList_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiConnectionList_Equals(x, y)` returns true and
+ * `cpiConnectionList_Equals(y, z)` returns true,
+ * then `cpiConnectionList_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `cpiConnectionList_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `cpiConnectionList_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `CPIConnectionList` instance.
+ * @param b A pointer to a `CPIConnectionList` instance.
+ * @return true if the two `CPIConnectionList` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIConnectionList *a = cpiConnectionList_Create();
+ * CPIConnectionList *b = cpiConnectionList_Create();
+ *
+ * if (cpiConnectionList_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool cpiConnectionList_Equals(const CPIConnectionList *a, const CPIConnectionList *b);
+
+/**
+ * The number of elements in the list
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return The number of elements in the list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t cpiConnectionList_Length(const CPIConnectionList *list);
+
+/**
+ * Returns a reference counted copy of the iptunnel entry.
+ *
+ * Caller must destroy the returned value.
+ * Will assert if you go beyond the end of the list.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIConnection *cpiConnectionList_Get(CPIConnectionList *list, size_t index);
+
+/**
+ * A JSON representation of the list
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *cpiConnectionList_ToJson(const CPIConnectionList *list);
+
+/**
+ * Constructs a list
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return An allocated list based on the JSON
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIConnectionList *cpiConnectionList_FromJson(PARCJSON *json);
+#endif // libccnx_cpi_ConnectionList_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ControlFacade.c b/libccnx-transport-rta/ccnx/api/control/cpi_ControlFacade.c
new file mode 100644
index 00000000..a0c2e7da
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ControlFacade.c
@@ -0,0 +1,159 @@
+/*
+ * 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 <parc/algol/parc_Memory.h>
+
+#include <ccnx/api/control/cpi_ControlFacade.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+#include <ccnx/common/ccnx_Name.h>
+
+static const char _NotificationIndicator[] = "notificationWrapper";
+static const char _NotificationPayload[] = "notificationPayload";
+
+
+// ===========================================================================================================
+
+
+CCNxControl *
+ccnxControlFacade_CreateCPI(PARCJSON *ccnx_json)
+{
+ assertNotNull(ccnx_json, "Parameter ccnx_json must be non-null");
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+
+ ccnxTlvDictionary_PutJson(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, ccnx_json);
+
+ return dictionary;
+}
+
+CCNxControl *
+ccnxControlFacade_CreateNotification(PARCJSON *payload)
+{
+ assertNotNull(payload, "Parameter ccnx_json must be non-null");
+
+ CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateControl();
+
+ // Create a new JSON object that indicates that this is a notification. Wrap it around
+ // the supplied JSON object.
+
+ PARCJSON *notificationWrapper = parcJSON_Create();
+ parcJSON_AddBoolean(notificationWrapper, _NotificationIndicator, true);
+ parcJSON_AddObject(notificationWrapper, _NotificationPayload, payload);
+ ccnxTlvDictionary_PutJson(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, notificationWrapper);
+ parcJSON_Release(&notificationWrapper);
+
+ return dictionary;
+}
+
+PARCJSON *
+ccnxControlFacade_GetJson(const CCNxTlvDictionary *controlDictionary)
+{
+ ccnxControlFacade_AssertValid(controlDictionary);
+ PARCJSON *controlJSON = ccnxTlvDictionary_GetJson(controlDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+
+ if (ccnxControlFacade_IsNotification(controlDictionary)) {
+ PARCJSONValue *wrappedJSON = parcJSON_GetValueByName(controlJSON, _NotificationPayload);
+ controlJSON = parcJSONValue_GetJSON(wrappedJSON);
+ }
+
+ return controlJSON;
+}
+
+bool
+ccnxControlFacade_IsCPI(const CCNxTlvDictionary *controlDictionary)
+{
+ bool result = false;
+ ccnxControlFacade_AssertValid(controlDictionary);
+
+ result = ccnxTlvDictionary_IsControl(controlDictionary);
+
+ PARCJSON *controlJSON = ccnxTlvDictionary_GetJson(controlDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+ if (controlJSON != NULL) {
+ if (parcJSON_GetValueByName(controlJSON, _NotificationIndicator) != NULL) {
+ // this is a notification
+ result = false;
+ }
+ }
+ return result;
+}
+
+bool
+ccnxControlFacade_IsNotification(const CCNxTlvDictionary *controlDictionary)
+{
+ bool result = false;
+
+ ccnxControlFacade_AssertValid(controlDictionary);
+
+ PARCJSON *controlJSON = ccnxTlvDictionary_GetJson(controlDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD);
+ if (controlJSON != NULL && (parcJSON_GetValueByName(controlJSON, _NotificationIndicator) != NULL)) {
+ result = true;
+ }
+ return result;
+}
+
+void
+ccnxControlFacade_Display(const CCNxTlvDictionary *contentDictionary, int indentation)
+{
+ ccnxTlvDictionary_Display(contentDictionary, indentation);
+}
+
+char *
+ccnxControlFacade_ToString(const CCNxTlvDictionary *contentDictionary)
+{
+ char *string;
+ char *jsonString = NULL;
+
+ PARCJSON *json = ccnxControlFacade_GetJson(contentDictionary);
+ if (json != NULL) {
+ jsonString = parcJSON_ToString(json);
+ }
+
+ int failure = asprintf(&string, "CCNxControl { isCPI=%s, isNotification=%s, JSON=\"%s\"}",
+ ccnxControlFacade_IsCPI(contentDictionary) ? "true" : "false",
+ ccnxControlFacade_IsNotification(contentDictionary) ? "true" : "false",
+ jsonString != NULL ? jsonString : "NULL");
+
+
+ if (jsonString) {
+ parcMemory_Deallocate((void **) &jsonString);
+ }
+
+ assertTrue(failure > -1, "Error asprintf");
+
+ char *result = parcMemory_StringDuplicate(string, strlen(string));
+ free(string);
+
+ return result;
+}
+
+void
+ccnxControlFacade_AssertValid(const CCNxTlvDictionary *controlDictionary)
+{
+ assertNotNull(controlDictionary, "Parameter must be a non-null CCNxControlFacade pointer");
+
+
+ assertTrue(ccnxTlvDictionary_IsValueJson(controlDictionary,
+ CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD), "Does not have JSON payload");
+ assertTrue(ccnxTlvDictionary_IsControl(controlDictionary), "Does not have type set");
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ControlFacade.h b/libccnx-transport-rta/ccnx/api/control/cpi_ControlFacade.h
new file mode 100644
index 00000000..26d84f22
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ControlFacade.h
@@ -0,0 +1,202 @@
+/*
+ * 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 cpi_ControlFacade.h
+ * @ingroup Utility
+ * @brief <#Brief Description#>
+ *
+ * A ControlFacade has several flavors. A Notification is a spontaneous message
+ * sent as an indication of some state or condition. A CPI (ControlPlaneInterface)
+ * message is a Request/Reponse protocol used to manage the Transport.
+ *
+ * The ccnxControlFacade takes ownership of the JSON object
+ * and will destroy it when it's Destroy is called.
+ *
+ * If put inside a CCNxMetaMessage and sent to the Transport, the Transport
+ * takes ownership of the CCNxMetaMessage and will thus be responsible for
+ * destroying the object.
+ *
+ */
+#ifndef libccnx_ccnx_ControlFacade_h
+#define libccnx_ccnx_ControlFacade_h
+
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/api/control/cpi_ControlMessage.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+typedef enum {
+ CCNxControlMessage_Unknown = 0,
+ CCNxControlMessage_CPI = 1,
+ CCNxControlMessage_Notify = 2
+} CCNxControlFacadeType;
+
+// =====================
+
+/**
+ * Creates a Nofification control message from the supplied JSON object.
+ *
+ * The newly created instance must eventually be released by calling
+ * {@link ccnxControl_Release}.
+ *
+ * @param ccnxJson the JSON object to include in the message.
+ * @return A `CCNxControl` message.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxControl *ccnxControlFacade_CreateNotification(PARCJSON *ccnxJson);
+
+/**
+ * Creates a CPI message from the supplied JSON object.
+ *
+ * The newly created instance must eventually be released by calling
+ * {@link ccnxControl_Release}.
+ *
+ * @param ccnxJson the JSON to include with the message.
+ * @return A `CCNxControl` message.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxControl *ccnxControlFacade_CreateCPI(PARCJSON *ccnxJson);
+
+// =====================
+// Getters
+
+/**
+ * Return a pointer to the JSON object contained in the control message.
+ *
+ * <#Discussion#>
+ *
+ * @param controlDictionary the control message to retrieve the JSON from.
+ * @return the PARCJSON object from the control message.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *ccnxControlFacade_GetJson(const CCNxTlvDictionary *controlDictionary);
+
+/**
+ * Test whether a control message is a Notification.
+ *
+ * <#Discussion#>
+ *
+ * @param controlDictionary the control message to test.
+ * @return true if the control message is a Notification.
+ * @return false if the control message is not a Notification.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxControlFacade_IsNotification(const CCNxTlvDictionary *controlDictionary);
+
+/**
+ * Test whether a control message is a CPI (Control Plane Interface) message.
+ *
+ * <#Discussion#>
+ *
+ * @param controlDictionary the control message to test.
+ * @return true if the control message is a CPI message.
+ * @return false if the control message is not a CPI message.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool ccnxControlFacade_IsCPI(const CCNxTlvDictionary *controlDictionary);
+
+
+// =====================
+// Miscellaneous
+
+/**
+ * Print a human readable representation of the given `CCNxTlvDictionary` representing
+ * a control message.
+ *
+ * @param [in] name A pointer to the `CCNxTlvDictionary` instance representing a CCNxControl.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTlvDictionary *controlMessage = ccnxControlFacade_CreateCPI(...);
+ * ccnxControlFacade_Display(controlMessage);
+ * ...
+ * }
+ * @endcode
+ */
+void ccnxControlFacade_Display(const CCNxTlvDictionary *controlDictionary, int indentation);
+
+/**
+ * Produce a null-terminated string representation of the specified CCNxTlvDictionary instance
+ * representing a control message.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] name A pointer to the `CCNxTlvDictionary` instance representing a CCNxControl.
+ *
+ * @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
+ * {
+ * char *desc = ccnxControlFacade_ToString(controlDictionary);
+ * printf("%s\n", desc);
+ * parcMemory_Deallocate((void **) &desc);
+ *
+ * ccnxTlvDictionary_Release(&control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControlFacade_Display}
+ * @see {@link parcMemory_Deallocate}
+ */
+char *ccnxControlFacade_ToString(const CCNxTlvDictionary *controlDictionary);
+
+/**
+ * Assert that an instance of `CCNxTlvDictionary` is a valid control message.
+ *
+ * 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
+ * {
+ * CCNxControl *controlMessage = ccnxControlFacade_CreateCPI(...);
+ * ccnxControlFacade_AssertValid(controlMessage);
+ * ...
+ * }
+ * @endcode
+ */
+void ccnxControlFacade_AssertValid(const CCNxTlvDictionary *controlDictionary);
+#endif // libccnx_ccnx_ControlFacade_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ControlMessage.c b/libccnx-transport-rta/ccnx/api/control/cpi_ControlMessage.c
new file mode 100644
index 00000000..3150c2d3
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ControlMessage.c
@@ -0,0 +1,245 @@
+/*
+ * 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/api/control/cpi_ControlMessage.h>
+
+#include <ccnx/api/control/cpi_ControlFacade.h>
+
+#include <ccnx/api/notify/notify_Status.h>
+
+#include <ccnx/api/control/controlPlaneInterface.h>
+
+PARCJSON *
+ccnxControl_GetJson(const CCNxControl *control)
+{
+ return ccnxControlFacade_GetJson(control);
+}
+
+void
+ccnxControl_Display(const CCNxControl *control, int indentation)
+{
+ ccnxControlFacade_Display(control, indentation);
+}
+
+void
+ccnxControl_Release(CCNxControl **controlP)
+{
+ ccnxTlvDictionary_Release(controlP);
+}
+
+CCNxControl *
+ccnxControl_Acquire(const CCNxControl *control)
+{
+ return ccnxTlvDictionary_Acquire(control);
+}
+
+bool
+ccnxControl_IsACK(const CCNxControl *control)
+{
+ if (cpi_GetMessageType(control) == CPI_ACK) {
+ PARCJSON *json = ccnxControlFacade_GetJson(control);
+ return cpiAcks_IsAck(json);
+ }
+ return false;
+}
+
+bool
+ccnxControl_IsNACK(const CCNxControl *control)
+{
+ if (cpi_GetMessageType(control) == CPI_ACK) {
+ PARCJSON *json = ccnxControlFacade_GetJson(control);
+ return !cpiAcks_IsAck(json);
+ }
+ return false;
+}
+
+uint64_t
+ccnxControl_GetAckOriginalSequenceNumber(const CCNxControl *control)
+{
+ PARCJSON *json = ccnxControlFacade_GetJson(control);
+ return cpiAcks_GetAckOriginalSequenceNumber(json);
+}
+
+bool
+ccnxControl_IsNotification(const CCNxControl *control)
+{
+ return ccnxControlFacade_IsNotification(control);
+}
+
+NotifyStatus *
+ccnxControl_GetNotifyStatus(const CCNxControl *control)
+{
+ return notifyStatus_ParseJSON(ccnxControl_GetJson(control));
+}
+
+CCNxControl *
+ccnxControl_CreateCPIRequest(PARCJSON *json)
+{
+ return ccnxControlFacade_CreateCPI(json);
+}
+
+CCNxControl *
+ccnxControl_CreateAddRouteRequest(const CPIRouteEntry *route)
+{
+ PARCJSON *cpiRequest = cpiForwarding_CreateAddRouteRequest(route);
+ CCNxControl *result = ccnxControl_CreateCPIRequest(cpiRequest);
+ parcJSON_Release(&cpiRequest);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreateRemoveRouteRequest(const CPIRouteEntry *route)
+{
+ PARCJSON *cpiRequest = cpiForwarding_CreateRemoveRouteRequest(route);
+ CCNxControl *result = ccnxControl_CreateCPIRequest(cpiRequest);
+ parcJSON_Release(&cpiRequest);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreateSetStrategyRequest(const CPIForwardingStrategy *fwdStrategy)
+{
+ PARCJSON *cpiRequest = cpiForwarding_CreateSetStrategyRequest(fwdStrategy);
+ CCNxControl *result = ccnxControl_CreateCPIRequest(cpiRequest);
+ parcJSON_Release(&cpiRequest);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreateSetWldrRequest(const CPIManageWldr *cpiWldr)
+{
+ PARCJSON *cpiRequest = cpiLinks_CreateSetWldrRequest(cpiWldr);
+ CCNxControl *result = ccnxControl_CreateCPIRequest(cpiRequest);
+ parcJSON_Release(&cpiRequest);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreateRouteListRequest()
+{
+ PARCJSON *cpiRequest = cpiForwarding_CreateRouteListRequest();
+ CCNxControl *result = ccnxControl_CreateCPIRequest(cpiRequest);
+ parcJSON_Release(&cpiRequest);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreateConnectionListRequest()
+{
+ PARCJSON *cpiRequest = cpiLinks_CreateConnectionListRequest();
+ CCNxControl *result = ccnxControl_CreateCPIRequest(cpiRequest);
+ parcJSON_Release(&cpiRequest);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreateInterfaceListRequest()
+{
+ PARCJSON *cpiRequest = cpiLinks_CreateInterfaceListRequest();
+ CCNxControl *result = ccnxControl_CreateCPIRequest(cpiRequest);
+ parcJSON_Release(&cpiRequest);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreateAddRouteToSelfRequest(const CCNxName *name)
+{
+ CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(name);
+ CCNxControl *result = ccnxControl_CreateAddRouteRequest(route);
+ cpiRouteEntry_Destroy(&route);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreateRemoveRouteToSelfRequest(const CCNxName *name)
+{
+ CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(name);
+ CCNxControl *result = ccnxControl_CreateRemoveRouteRequest(route);
+ cpiRouteEntry_Destroy(&route);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreatePauseInputRequest()
+{
+ PARCJSON *cpiRequest = cpi_CreatePauseInputRequest();
+ CCNxControl *result = ccnxControl_CreateCPIRequest(cpiRequest);
+ parcJSON_Release(&cpiRequest);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreateFlushRequest(void)
+{
+ PARCJSON *cpiRequest = cpi_CreateFlushRequest();
+ CCNxControl *result = ccnxControl_CreateCPIRequest(cpiRequest);
+ parcJSON_Release(&cpiRequest);
+ return result;
+}
+
+bool
+ccnxControl_IsCPI(const CCNxControl *controlMsg)
+{
+ return ccnxControlFacade_IsCPI((CCNxTlvDictionary *) controlMsg);
+}
+
+CCNxControl *
+ccnxControl_CreateIPTunnelRequest(const CPIInterfaceIPTunnel *tunnel)
+{
+ PARCJSON *request = cpiLinks_CreateIPTunnel(tunnel);
+ CCNxControl *result = ccnxControl_CreateCPIRequest(request);
+ parcJSON_Release(&request);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreateCancelFlowRequest(const CCNxName *name)
+{
+ PARCJSON *request = cpiCancelFlow_CreateRequest(name);
+ CCNxControl *result = ccnxControl_CreateCPIRequest(request);
+ parcJSON_Release(&request);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreateCacheStoreRequest(bool activate)
+{
+ PARCJSON *cpiRequest = cpiManageChaces_CreateCacheStoreRequest(activate);
+ CCNxControl *result = ccnxControl_CreateCPIRequest(cpiRequest);
+ parcJSON_Release(&cpiRequest);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreateCacheServeRequest(bool activate)
+{
+ PARCJSON *cpiRequest = cpiManageChaces_CreateCacheServeRequest(activate);
+ CCNxControl *result = ccnxControl_CreateCPIRequest(cpiRequest);
+ parcJSON_Release(&cpiRequest);
+ return result;
+}
+
+CCNxControl *
+ccnxControl_CreateCacheClearRequest()
+{
+ PARCJSON *cpiRequest = cpiManageChaces_CreateCacheClearRequest();
+ CCNxControl *result = ccnxControl_CreateCPIRequest(cpiRequest);
+ parcJSON_Release(&cpiRequest);
+ return result;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ControlMessage.h b/libccnx-transport-rta/ccnx/api/control/cpi_ControlMessage.h
new file mode 100644
index 00000000..84f085e7
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ControlMessage.h
@@ -0,0 +1,587 @@
+/*
+ * 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_Control.h
+ * @brief This is a stack control message.
+ *
+ * This may induce other Control messages for the stack, for the Forwarder, or potentially
+ * for the network.
+ *
+ */
+
+#ifndef libccnx_ccnx_Control_h
+#define libccnx_ccnx_Control_h
+
+#include <stdint.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+#include <ccnx/api/notify/notify_Status.h>
+
+#include <ccnx/api/control/cpi_RouteEntry.h>
+#include <ccnx/api/control/cpi_ForwardingStrategy.h>
+#include <ccnx/api/control/cpi_ManageWldr.h>
+#include <ccnx/api/control/cpi_InterfaceIPTunnel.h>
+
+/**
+ * @typedef CCNxControl
+ * @brief Control message for CCNx.
+ */
+typedef CCNxTlvDictionary CCNxControl;
+
+/**
+ * Increase the number of references to a `CCNxControl` instance.
+ *
+ * Note that new `CCNxControl` is not created,
+ * only that the given `CCNxControl` reference count is incremented.
+ * Discard the reference by invoking {@link ccnxControl_Release()}.
+ *
+ * @param [in] control A pointer to the original instance.
+ * @return The value of the input parameter @p control.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * CCNxControl *control = ccnxControl_Acquire(instance);
+ *
+ * ccnxControl_Release(&control);
+ *
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_Release}
+ */
+CCNxControl *ccnxControl_Acquire(const CCNxControl *control);
+
+/**
+ * Print a human readable representation of the given `CCNxControl` instance.
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] control A pointer to the instance to display.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxControl *control = < ... >
+ *
+ * ccnxControl_Display(control, 4);
+ *
+ * ccnxControl_Release(&control);
+ * }
+ * @endcode
+ *
+ */
+void ccnxControl_Display(const CCNxControl *control, int indentation);
+
+/**
+ * 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] controlP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxControl *control = < ... >
+ *
+ * ccnxControl_Release(&control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_Acquire}
+ */
+void ccnxControl_Release(CCNxControl **controlP);
+
+/**
+ * Return the original sequence number to which an ACK corresponds.
+ *
+ * Control plane messages contain sequence numbers. When an ACK is received, this function
+ * returns the sequence number of the control plane message being ACKed.
+ *
+ * @param [in] control A pointer to a `CCNxControl` instance.
+ *
+ * @return The sequence number of the control plane message being ACKed.
+ *
+ * Example:
+ * @code
+ * {
+ * uint64_t originalSequenceNumber = ccnxControl_GetAckOriginalSequenceNumber(control);
+ * }
+ * @endcode
+ */
+uint64_t ccnxControl_GetAckOriginalSequenceNumber(const CCNxControl *control);
+
+/**
+ * Return true if the specified `CCNxControl` instance is a Notification.
+ *
+ * @param [in] control A pointer to a `CCNxControl` instance.
+ *
+ * @return `true` if the specified `CCNxControl` instance is a Notification message.
+ * @return `false` if the specified `CCNxControl` instance is not a Notification message.
+ *
+ * Example:
+ * @code
+ * {
+ * bool isNotification = ccnxControl_IsNotification(control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_IsACK}
+ */
+bool ccnxControl_IsNotification(const CCNxControl *control);
+
+/**
+ * Return `true` if the specified `CCNxControl` instance is an ACK message carrying an ACK (not a NACK)
+ *
+ * An acknolwedgement message can be either a positive (ACK) or negative (NACK) acknowlegement.
+ * In both cases, it carries the original sequence number of the message being ACKed or NACKed.
+ *
+ * @param [in] control A pointer to a `CCNxControl` instance.
+ *
+ * @return `true` if the specified `CCNxControl` instance is an Ack message.
+ * @return `false` if the specified `CCNxControl` instance is not an Ack message.
+ *
+ * Example:
+ * @code
+ * {
+ * bool isAck = ccnxControl_IsACK(control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_IsNotification}
+ */
+bool ccnxControl_IsACK(const CCNxControl *control);
+
+/**
+ * Return `true` if the specified `CCNxControl` instance is an ACK message carrying a NACK (not a ACK)
+ *
+ * An acknolwedgement message can be either a positive (ACK) or negative (NACK) acknowlegement.
+ * In both cases, it carries the original sequence number of the message being ACKed or NACKed.
+ *
+ * @param [in] control A pointer to a `CCNxControl` instance.
+ *
+ * @return `true` if the specified `CCNxControl` is an NACK.
+ * @return `false` if the specified `CCNxControl` instance is not an NAck message.
+ *
+ * Example:
+ * @code
+ * {
+ * bool isAck = ccnxControl_IsACK(control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_IsNotification}
+ */
+bool ccnxControl_IsNACK(const CCNxControl *control);
+
+/**
+ * Get the {@link NotifyStatus} from a `CCNxControl` instance, if it exists.
+ *
+ * This function creates a new instance of `NotifyStatus`, initialized from the specified
+ * `CCNxControl`, which must eventually be released by calling {@link notifyStatus_Release}().
+ * If the specified `CCNxControl` instance does not contain a `NotifyStatus`, this function will return NULL.
+ *
+ * @param [in] control A pointer to the instance of `CCNxControl` from which to retrieve the `NotifyStatus`.
+ *
+ * @return An instance of `NotifyStatus`, if it exists.
+ * @return NULL If the `CCNxControl` instance did not contain a `NotifyStatus`.
+ *
+ * Example:
+ * @code
+ * {
+ * NotifyStatus status = ccnxControl_GetNotifyStatus(control);
+ *
+ * notifyStatus_Release(&status);
+ * }
+ * @endcode
+ *
+ * @see {@link notifyStatus_Release}
+ * @see {@link NotifyStatus}
+ */
+NotifyStatus *ccnxControl_GetNotifyStatus(const CCNxControl *control);
+
+/**
+ * Create a new `CCNxControl` instance containing a request to add a route to the control plane.
+ *
+ * The new `CCNxControl` instance must eventually be released by calling {@link ccnxControl_Release()}.
+ *
+ * @param [in] route The {@link CPIRouteEntry} to add.
+ *
+ * @return A new `CCNxControl` instance encapsulating a request to add the specified route.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIRouteEntry *cpiRouteEntry = cpiRouteEntry_Create(...);
+ *
+ * CCNxControl *control = ccnxControl_CreateAddRouteRequest(cpiRouteEntry);
+ *
+ * cpiRouteEntry_Destroy(&cpiRouteEntry);
+ * ccnxControl_Release(&control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_CreateRemoveRouteRequest}
+ * @see {@link ccnxControl_Release}
+ */
+CCNxControl *ccnxControl_CreateAddRouteRequest(const CPIRouteEntry *route);
+
+/**
+ * Create a new `CCNxControl` instance containing a request to remove a route from the control plane.
+ *
+ * The new `CCNxControl` instance must eventually be released by calling {@link ccnxControl_Release}.
+ *
+ * @param [in] route The {@link CPIRouteEntry} to remove.
+ *
+ * @return A new `CCNxControl` instance encapsulating a request to remove the specified route.
+ *
+ * Example:
+ * @code
+ * {
+ * {
+ * CPIRouteEntry *cpiRouteEntry = cpiRouteEntry_Create(...);
+ *
+ * CCNxControl *control = ccnxControl_CreateRemoveRouteRequest(cpiRouteEntry);
+ *
+ * cpiRouteEntry_Destroy(&cpiRouteEntry);
+ * ccnxControl_Release(&control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_CreateAddRouteRequest}
+ * @see {@link ccnxControl_Release}
+ */
+CCNxControl *ccnxControl_CreateRemoveRouteRequest(const CPIRouteEntry *route);
+
+CCNxControl *ccnxControl_CreateSetStrategyRequest(const CPIForwardingStrategy *fwdStrategy);
+
+CCNxControl *ccnxControl_CreateSetWldrRequest(const CPIManageWldr *cpiWldr);
+
+/**
+ * Create a new `CCNxControl` instance containing a request to add a route for CCN messages matching the given {@link CCNxName}
+ * back to the caller's network interface.
+ *
+ * The created `CCNxControl` message describes to the forwarder that messages matching the specified `CCNxName` should be
+ * routed back to the caller. This is how to initiate listening for a name.
+ * The new `CCNxControl` instance must eventually be released by calling {@link ccnxControl_Release}.
+ *
+ * @param [in] name A pointer to a `CCNxName` instance containing the name to match against.
+ *
+ * @return A new `CCNxControl` instance encapsulating a request to add a route for the given `CCNxName` back to the caller's
+ * network interface.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/media/thingie");
+ *
+ * CCNxControl *control = ccnxControl_CreateAddRouteToSelfRequest(name);
+ * ...
+ *
+ * ccnxName_Release(&name);
+ * ccnxControl_Release(&control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_CreateRemoveRouteToSelfRequest}
+ * @see {@link ccnxControl_CreateAddRouteRequest}
+ * @see {@link ccnxControl_Release}
+ */
+CCNxControl *ccnxControl_CreateAddRouteToSelfRequest(const CCNxName *name);
+
+/**
+ * Create a new `CCNxControl` instance containing a request to remove a route to the caller for messages matching the specified
+ * {@link CCNxName}.
+ *
+ *
+ * The new `CCNxControl` instance must eventually be released by calling {@link ccnxControl_Release}.
+ *
+ * @param [in] name A pointer to a `CCNxName` instance containing the name to match against.
+ *
+ * @return A new `CCNxControl` instance encapsulating a request to remove the specified route.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/parc/csl/media/thingie");
+ *
+ * CCNxControl *control = ccnxControl_CreateRemoveRouteToSelfRequest(name);
+ * ...
+ *
+ * ccnxName_Release(&name);
+ * ccnxControl_Release(&control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_CreateAddRouteToSelfRequest}
+ * @see {@link ccnxControl_Release}
+ */
+CCNxControl *ccnxControl_CreateRemoveRouteToSelfRequest(const CCNxName *name);
+
+/**
+ * Create a new `CCNxControl` instance containing the specified CPI command, and including the
+ * flag indicating that it is a CPI message.
+ *
+ * The new `CCNxControl` instance must eventually be released by calling {@link ccnxControl_Release}.
+ *
+ * @param [in] json A pointer to a {@link PARCJSON} instance containing CPI command to wrap.
+ *
+ * @return A new `CCNxControl` instance containing the specified CPI command.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+ * PARCJSON *cpiRequest = cpiCancelFlow_CreateRequest(name);
+ * CCNxControl *control = ccnxControl_CreateCPIRequest(cpiRequest);
+ *
+ * ...
+ *
+ * parcJSON_Release(&cpiRequest);
+ * ccnxControl_Release(&control);
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_Release}
+ */
+CCNxControl *ccnxControl_CreateCPIRequest(PARCJSON *json);
+
+/**
+ * Create a new `CCNxControl` instance containing a "List Routes" request.
+ *
+ * The new `CCNxControl` instance must eventually be released by calling {@link ccnxControl_Release}.
+ *
+ * @return A new `CCNxControl` instance containing the request.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxControl *control = ccnxControl_CreateRouteListRequest();
+ * PARCJSON *json = ccnxControl_GetJson(control);
+ *
+ * ...
+ *
+ * ccnxControl_Release(&control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_Release}
+ */
+CCNxControl *ccnxControl_CreateRouteListRequest(void);
+
+/**
+ * Create a new `CCNxControl` instance containing a "List Connections" request.
+ *
+ * The new `CCNxControl` instance must eventually be released by calling {@link ccnxControl_Release}.
+ *
+ * @return A new `CCNxControl` instance containing the request.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxControl *control = ccnxControl_CreateRouteListRequest();
+ *
+ * ...
+ *
+ * ccnxControl_Release(&control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_Release}
+ */
+CCNxControl *ccnxControl_CreateConnectionListRequest(void);
+
+/**
+ * Create a new `CCNxControl` instance containing a "List Interfaces" request.
+ *
+ * The new `CCNxControl` instance must eventually be released by calling {@link ccnxControl_Release}.
+ *
+ * @return A new `CCNxControl` instance containing the request.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxControl *control = ccnxControl_CreateInterfaceListRequest();
+ *
+ * ...
+ *
+ * ccnxControl_Release(&control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_Release}
+ */
+CCNxControl *ccnxControl_CreateInterfaceListRequest(void);
+
+/**
+ * Create a new `CCNxControl` instance containing a "Pause Input" request.
+ *
+ * The new `CCNxControl` instance must eventually be released by calling {@link ccnxControl_Release}.
+ *
+ * @return A new `CCNxControl` instance containing the request.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxControl *control = ccnxControl_CreatePauseInputRequest();
+ *
+ * ...
+ *
+ * ccnxControl_Release(&control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_Release}
+ * @see {@link cpi_CreatePauseInputRequest}
+ */
+CCNxControl *ccnxControl_CreatePauseInputRequest(void);
+
+
+/**
+ * Creates a request to flush the output. The ForwarderConnector will ACK the request.
+ *
+ * When the user recieves an ACK with the corresponding sequence number as this request, the
+ * user knows that all ouptut prior to that request has been processed.
+ *
+ * @retval non-null An allocated CCnxControl message
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxControl *ccnxControl_CreateFlushRequest(void);
+
+/**
+ * Create a new `CCNxControl` instance containing a "Cancel Flow" request.
+ *
+ * The new `CCNxControl` instance must eventually be released by calling {@link ccnxControl_Release}.
+ * @param [in] name A pointer to a `CCNxName`.
+ *
+ * @return A new `CCNxControl` instance containing the request.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+ * CCNxControl *control = ccnxControl_CreateCancelFlowRequest(name);
+ *
+ * ...
+ *
+ * ccnxControl_Release(&control);
+ * ccnxName_Release(&name);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_Release}
+ */
+CCNxControl *ccnxControl_CreateCancelFlowRequest(const CCNxName *name);
+
+/**
+ * Create a new `CCNxControl` instance containing a "Create IP Tunnel" request.
+ *
+ * The new `CCNxControl` instance must eventually be released by calling {@link ccnxControl_Release}.
+ *
+ * @param [in] tunnel An instance of `CPIInterfaceIPTunnel` to be included.
+ * @return A new `CCNxControl` instance containing the request.
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr_in sockaddr_any;
+ * memset(&sockaddr_any, 0, sizeof(sockaddr_any));
+ * sockaddr_any.sin_family = PF_INET;
+ * sockaddr_any.sin_addr.s_addr = INADDR_ANY;
+ *
+ * CPIAddress *source = cpiAddress_CreateFromInet(&sockaddr_any);
+ *
+ * struct sockaddr_in sockaddr_dst;
+ * memset(&sockaddr_dst, 0, sizeof(sockaddr_dst));
+ * sockaddr_dst.sin_family = PF_INET;
+ * sockaddr_dst.sin_port = htons(9999);
+ * inet_pton(AF_INET, "127.0.0.1", &(sockaddr_dst.sin_addr));
+ *
+ * CPIAddress *destination = cpiAddress_CreateFromInet(&sockaddr_dst);
+ *
+ * CPIInterfaceIPTunnel *tunnel = cpiInterfaceIPTunnel_Create(0, source, destination, IPTUN_TCP);
+ * CCNxControl *control = ccnxControl_CreateIPTunnelRequest(tunnel);
+ *
+ * ...
+ *
+ * ccnxControl_Release(&control);
+ * cpiInterfaceIPTunnel_Destroy(&tunnel);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_Release}
+ */
+CCNxControl *ccnxControl_CreateIPTunnelRequest(const CPIInterfaceIPTunnel *tunnel);
+
+
+CCNxControl *ccnxControl_CreateCacheStoreRequest(bool activate);
+CCNxControl *ccnxControl_CreateCacheServeRequest(bool activate);
+CCNxControl *ccnxControl_CreateCacheClearRequest();
+
+/**
+ * Return true if the specified `CCNxControl` instance is an a CPI request.
+ *
+ * @param [in] controlMsg A pointer to a `CCNxControl` instance.
+ *
+ * @return `true` if the specified `CCNxControl` instance is a CPI request.
+ * @return `false` if the specified `CCNxControl` instance is not a CPI request.
+ *
+ * Example:
+ * @code
+ * {
+ * bool isCPI = ccnxControl_IsCPI(control);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxControl_IsNotification}
+ */
+bool ccnxControl_IsCPI(const CCNxControl *controlMsg);
+
+/**
+ * Return the underlying CPI request from the specified `CCNxControl`.
+ *
+ * @return A pointer to the underlying CPI request object.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxControl *control = ccnxControl_CreateRouteListRequest();
+ * PARCJSON *json = ccnxControl_GetJson(control);
+ *
+ * ...
+ *
+ * ccnxControl_Release(&control);
+ * }
+ * @endcode
+ *
+ * @see ccnxControl_Release
+ */
+PARCJSON *ccnxControl_GetJson(const CCNxControl *control);
+#endif // libccnx_ccnx_Control_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Forwarding.c b/libccnx-transport-rta/ccnx/api/control/cpi_Forwarding.c
new file mode 100644
index 00000000..3cd836d2
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_Forwarding.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/api/control/controlPlaneInterface.h>
+#include <ccnx/api/control/cpi_Forwarding.h>
+#include <LongBow/runtime.h>
+
+#include "cpi_private.h"
+
+static const char *cpiRegister = "REGISTER";
+static const char *cpiUnregister = "UNREGISTER";
+static const char *cpiRouteList = "ROUTE_LIST";
+static const char *cpiSetStrategy = "SET_STRATEGY";
+
+PARCJSON *
+cpiForwarding_CreateSetStrategyRequest(CPIForwardingStrategy *fwdStrategy)
+{
+ PARCJSON *json = cpiForwardingStrategy_ToJson(fwdStrategy);
+ PARCJSON *result = cpi_CreateRequest(cpiSetStrategy, json);
+ parcJSON_Release(&json);
+
+ return result;
+}
+
+PARCJSON *
+cpiForwarding_CreateAddRouteRequest(const CPIRouteEntry *route)
+{
+ PARCJSON *routeAsJSON = cpiRouteEntry_ToJson(route);
+ PARCJSON *result = cpi_CreateRequest(cpiRegister, routeAsJSON);
+ parcJSON_Release(&routeAsJSON);
+
+ return result;
+}
+
+PARCJSON *
+cpiForwarding_CreateRemoveRouteRequest(const CPIRouteEntry *route)
+{
+ PARCJSON *routeAsJSON = cpiRouteEntry_ToJson(route);
+ PARCJSON *result = cpi_CreateRequest(cpiUnregister, routeAsJSON);
+ parcJSON_Release(&routeAsJSON);
+
+ return result;
+}
+
+PARCJSON *
+cpiForwarding_AddRouteToSelf(const CCNxName *prefix)
+{
+ CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(prefix);
+ PARCJSON *result = cpiForwarding_AddRoute(route);
+ cpiRouteEntry_Destroy(&route);
+ return result;
+}
+
+PARCJSON *
+cpiForwarding_RemoveRouteToSelf(const CCNxName *prefix)
+{
+ CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(prefix);
+ PARCJSON *result = cpiForwarding_RemoveRoute(route);
+ cpiRouteEntry_Destroy(&route);
+ return result;
+}
+
+PARCJSON *
+cpiForwarding_AddRoute(const CPIRouteEntry *route)
+{
+ PARCJSON *operation = cpiRouteEntry_ToJson(route);
+ PARCJSON *result = cpi_CreateRequest(cpiRegister, operation);
+ parcJSON_Release(&operation);
+
+ return result;
+}
+
+PARCJSON *
+cpiForwarding_RemoveRoute(const CPIRouteEntry *route)
+{
+ PARCJSON *operation = cpiRouteEntry_ToJson(route);
+ PARCJSON *result = cpi_CreateRequest(cpiUnregister, operation);
+ parcJSON_Release(&operation);
+
+ return result;
+}
+
+CPIRouteEntry *
+cpiForwarding_RouteFromControlMessage(CCNxControl *control)
+{
+ assertNotNull(control, "Parameter control must be non-null");
+ PARCJSON *json = ccnxControl_GetJson(control);
+
+ PARCJSONPair *routeOpPair = cpi_ParseRequest(json);
+ PARCJSON *routeJson = parcJSONValue_GetJSON(parcJSONPair_GetValue(routeOpPair));
+
+ CPIRouteEntry *route = cpiRouteEntry_FromJson(routeJson);
+
+ return route;
+}
+
+CPIForwardingStrategy *
+cpiForwarding_ForwardingStrategyFromControlMessage(CCNxControl *control)
+{
+ assertNotNull(control, "Parameter control must be non-null");
+ PARCJSON *json = ccnxControl_GetJson(control);
+
+ PARCJSONPair *fwdStrOpPair = cpi_ParseRequest(json);
+ PARCJSON *fwdStrategyJson = parcJSONValue_GetJSON(parcJSONPair_GetValue(fwdStrOpPair));
+ CPIForwardingStrategy *fwdStrategy = cpiForwardingStrategy_FromJson(fwdStrategyJson);
+
+ return fwdStrategy;
+}
+
+const char *
+cpiForwarding_AddRouteJsonTag()
+{
+ return cpiRegister;
+}
+
+const char *
+cpiForwarding_RemoveRouteJsonTag()
+{
+ return cpiUnregister;
+}
+
+const char *
+cpiForwarding_RouteListJsonTag()
+{
+ return cpiRouteList;
+}
+
+const char *
+cpiForwarding_SetStrategyJsonTag()
+{
+ return cpiSetStrategy;
+}
+
+
+PARCJSON *
+cpiForwarding_CreateRouteListRequest()
+{
+ PARCJSON *json = parcJSON_Create();
+ PARCJSON *result = cpi_CreateRequest(cpiRouteList, json);
+ parcJSON_Release(&json);
+
+ return result;
+}
+
+CPIRouteEntryList *
+cpiForwarding_RouteListFromControlMessage(CCNxControl *control)
+{
+ PARCJSON *json = ccnxControl_GetJson(control);
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpiRequest_GetJsonTag());
+ if (value == NULL) {
+ value = parcJSON_GetValueByName(json, cpiResponse_GetJsonTag());
+ }
+ PARCJSON *innerJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(innerJson, cpiRouteList);
+ PARCJSON *operation = parcJSONValue_GetJSON(value);
+ return cpiRouteEntryList_FromJson(operation);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Forwarding.h b/libccnx-transport-rta/ccnx/api/control/cpi_Forwarding.h
new file mode 100644
index 00000000..258939fd
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_Forwarding.h
@@ -0,0 +1,242 @@
+/*
+ * 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 cpi_Forwarding.h
+ * @brief CPI Forwarding
+ *
+ */
+#ifndef libccnx_cpi_ManageForwarding_h
+#define libccnx_cpi_ManageForwarding_h
+
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/api/control/cpi_ControlMessage.h>
+#include <ccnx/api/control/cpi_Address.h>
+#include <ccnx/api/control/cpi_NameRouteType.h>
+#include <ccnx/api/control/cpi_RouteEntry.h>
+#include <ccnx/api/control/cpi_RouteEntryList.h>
+#include <ccnx/api/control/cpi_ForwardingStrategy.h>
+
+/**
+ * Generate a request for a list all routes
+ *
+ * The transport should resond with a CPI Response message.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *cpiForwarding_CreateRouteListRequest();
+
+/**
+ * Parse a control message into a list of interfaces
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIRouteEntryList *cpiForwarding_RouteListFromControlMessage(CCNxControl *response);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *cpiForwarding_CreateAddRouteRequest(const CPIRouteEntry *route);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *cpiForwarding_CreateRemoveRouteRequest(const CPIRouteEntry *route);
+
+/**
+ * Simplified form of <code>cpiForwarding_AddRoute</code> to add a route to the current transport
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *cpiForwarding_AddRouteToSelf(const CCNxName *prefix);
+
+/**
+ * Simplified form of <code>cpiForwarding_RemoveRoute</code> to remove a route to the current transport
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *cpiForwarding_RemoveRouteToSelf(const CCNxName *prefix);
+
+/**
+ * Creates a control message representing the route
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *cpiForwarding_AddRoute(const CPIRouteEntry *route);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *cpiForwarding_RemoveRoute(const CPIRouteEntry *route);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIRouteEntry *cpiForwarding_RouteFromControlMessage(CCNxControl *control);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const char *cpiForwarding_AddRouteJsonTag();
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const char *cpiForwarding_RemoveRouteJsonTag();
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const char *cpiForwarding_RouteListJsonTag();
+
+PARCJSON *cpiForwarding_CreateSetStrategyRequest();
+const char *cpiForwarding_SetStrategyJsonTag();
+CPIForwardingStrategy *cpiForwarding_ForwardingStrategyFromControlMessage(CCNxControl *control);
+#endif // libccnx_cpi_ManageForwarding_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ForwardingStrategy.c b/libccnx-transport-rta/ccnx/api/control/cpi_ForwardingStrategy.c
new file mode 100644
index 00000000..89cce66f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ForwardingStrategy.c
@@ -0,0 +1,158 @@
+/*
+ * 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 <ccnx/api/control/cpi_ForwardingStrategy.h>
+#include <ccnx/api/control/controlPlaneInterface.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <limits.h>
+
+#include <LongBow/runtime.h>
+
+static const char *cpiPrefix = "PREFIX";
+static const char *cpiStrategy = "STRATEGY";
+
+struct cpi_forwarding_strategy {
+ CCNxName *prefix;
+ char *strategy;
+};
+
+void
+cpiForwardingStrategy_Destroy(CPIForwardingStrategy **fwdStrategyPtr)
+{
+ assertNotNull(fwdStrategyPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*fwdStrategyPtr, "Parameter must dereference to non-null pointer");
+ CPIForwardingStrategy *fwdStrategy = *fwdStrategyPtr;
+
+ ccnxName_Release(&fwdStrategy->prefix);
+ parcMemory_Deallocate((void **) &fwdStrategy->strategy);
+
+ parcMemory_Deallocate((void **) &fwdStrategy);
+ *fwdStrategyPtr = NULL;
+}
+
+CPIForwardingStrategy *
+cpiForwardingStrategy_Create(CCNxName *prefix, char *strategy)
+{
+ CPIForwardingStrategy *fwdStrategy = parcMemory_AllocateAndClear(sizeof(fwdStrategy));
+ assertNotNull(fwdStrategy, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(fwdStrategy));
+
+ fwdStrategy->prefix = prefix;
+ fwdStrategy->strategy = parcMemory_StringDuplicate(strategy, strlen(strategy));
+
+ return fwdStrategy;
+}
+
+char *
+cpiForwardingStrategy_ToString(CPIForwardingStrategy *fwdStrategy)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ char *ccnxName = ccnxName_ToString(cpiForwardingStrategy_GetPrefix(fwdStrategy));
+ parcBufferComposer_PutString(composer, ccnxName);
+ parcMemory_Deallocate((void **) &ccnxName);
+
+ parcBufferComposer_PutString(composer, cpiForwardingStrategy_GetStrategy(fwdStrategy));
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ parcBufferComposer_Release(&composer);
+ return result;
+}
+
+
+CPIForwardingStrategy *
+cpiForwardingStrategy_Copy(const CPIForwardingStrategy *original)
+{
+ assertNotNull(original, "Parameter a must be non-null");
+ CPIForwardingStrategy *copy = cpiForwardingStrategy_Create(ccnxName_Copy(original->prefix),
+ parcMemory_StringDuplicate(original->strategy, strlen(original->strategy)));
+
+ return copy;
+}
+
+
+
+bool
+cpiForwardingStrategy_Equals(const CPIForwardingStrategy *a, const CPIForwardingStrategy *b)
+{
+ assertNotNull(a, "Parameter a must be non-null");
+ assertNotNull(b, "Parameter b must be non-null");
+ if (a == b) {
+ return true;
+ }
+
+ if (ccnxName_Equals(a->prefix, b->prefix) && (strcmp(a->strategy, b->strategy) == 0)) {
+ return true;
+ }
+
+ return false;
+}
+
+const CCNxName *
+cpiForwardingStrategy_GetPrefix(const CPIForwardingStrategy *fwdStrategy)
+{
+ assertNotNull(fwdStrategy, "Parameter must be non-null");
+ return fwdStrategy->prefix;
+}
+
+const char *
+cpiForwardingStrategy_GetStrategy(const CPIForwardingStrategy *fwdStrategy)
+{
+ assertNotNull(fwdStrategy, "Parameter must be non-null");
+ return fwdStrategy->strategy;
+}
+
+PARCJSON *
+cpiForwardingStrategy_ToJson(const CPIForwardingStrategy *fwdStrategy)
+{
+ assertNotNull(fwdStrategy, "Parameter must be non-null");
+
+ PARCJSON *fwdStrategyJson = parcJSON_Create();
+ char *uri = ccnxName_ToString(fwdStrategy->prefix);
+ parcJSON_AddString(fwdStrategyJson, cpiPrefix, uri);
+ parcMemory_Deallocate((void **) &uri);
+
+ parcJSON_AddString(fwdStrategyJson, cpiStrategy, fwdStrategy->strategy);
+
+ return fwdStrategyJson;
+}
+
+CPIForwardingStrategy *
+cpiForwardingStrategy_FromJson(PARCJSON *json)
+{
+ assertNotNull(json, "Parameter json must be non-null");
+ PARCJSON *fwdStrategyJson = json;
+
+ PARCJSONValue *value = parcJSON_GetValueByName(fwdStrategyJson, cpiPrefix);
+ assertNotNull(value, "Couldn't locate tag %s in: %s", cpiPrefix, parcJSON_ToString(json));
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ CCNxName *prefix = ccnxName_CreateFromCString(parcBuffer_Overlay(sBuf, 0));
+
+ value = parcJSON_GetValueByName(fwdStrategyJson, cpiStrategy);
+ assertNotNull(value, "Couldn't locate tag %s in: %s", cpiStrategy, parcJSON_ToString(json));
+ sBuf = parcJSONValue_GetString(value);
+ char *strategy = parcBuffer_Overlay(sBuf, 0);
+
+ CPIForwardingStrategy *fwdStrategy = cpiForwardingStrategy_Create(prefix, strategy);
+
+ return fwdStrategy;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ForwardingStrategy.h b/libccnx-transport-rta/ccnx/api/control/cpi_ForwardingStrategy.h
new file mode 100644
index 00000000..b50dff96
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ForwardingStrategy.h
@@ -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.
+ */
+
+#ifndef libccnx_cpi_ForwardingStrategy_h
+#define libccnx_cpi_ForwardingStrategy_h
+
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/api/control/cpi_Address.h>
+
+#include <parc/algol/parc_JSON.h>
+
+struct cpi_forwarding_strategy;
+/**
+ * @typedef CPIForwardingStrategy
+ * @brief A representation of a forwarding strategy.
+ */
+typedef struct cpi_forwarding_strategy CPIForwardingStrategy;
+
+/**
+ */
+
+
+void cpiForwardingStrategy_Destroy(CPIForwardingStrategy **fwdStrategyPtr);
+
+CPIForwardingStrategy *cpiForwardingStrategy_Create(CCNxName *prefix, char *strategy);
+
+char *cpiForwardingStrategy_ToString(CPIForwardingStrategy *fwdStrategy);
+
+CPIForwardingStrategy *cpiForwardingStrategy_Copy(const CPIForwardingStrategy *original);
+
+bool cpiForwardingStrategy_Equals(const CPIForwardingStrategy *a, const CPIForwardingStrategy *b);
+
+const CCNxName *cpiForwardingStrategy_GetPrefix(const CPIForwardingStrategy *fwdStrategy);
+
+const char *cpiForwardingStrategy_GetStrategy(const CPIForwardingStrategy *fwdStrategy);
+
+PARCJSON *cpiForwardingStrategy_ToJson(const CPIForwardingStrategy *fwdStrategy);
+
+CPIForwardingStrategy *cpiForwardingStrategy_FromJson(PARCJSON *json);
+
+#endif // libccnx_cpi_ForwardingStrategy_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Interface.c b/libccnx-transport-rta/ccnx/api/control/cpi_Interface.c
new file mode 100644
index 00000000..320ca11d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_Interface.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 <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <ccnx/api/control/cpi_AddressList.h>
+#include <ccnx/api/control/cpi_Interface.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Object.h>
+
+#include <LongBow/runtime.h>
+
+struct cpi_interface {
+ char *name;
+ unsigned interfaceIndex;
+ bool loopback;
+ bool supportMulticast;
+ unsigned mtu;
+
+ CPIAddressList *addressList;
+};
+
+char *
+cpiInterface_ToString(const CPIInterface *interface)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcBufferComposer_Format(composer, "%3u %10s %1s%1s %8u ",
+ interface->interfaceIndex,
+ interface->name,
+ interface->loopback ? "l" : " ",
+ interface->supportMulticast ? "m" : " ",
+ interface->mtu);
+
+ for (size_t i = 0; i < cpiAddressList_Length(interface->addressList); i++) {
+ cpiAddress_BuildString(cpiAddressList_GetItem(interface->addressList, i), composer);
+ if (i < (cpiAddressList_Length(interface->addressList) - 1)) {
+ parcBufferComposer_PutStrings(composer, "\n", NULL);
+ }
+ }
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ return result;
+}
+
+CPIInterface *
+cpiInterface_Create(const char *name, unsigned interfaceIndex, bool loopback, bool supportMulticast, unsigned mtu)
+{
+ CPIInterface *iface = parcMemory_AllocateAndClear(sizeof(CPIInterface));
+
+ assertNotNull(iface, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIInterface));
+ iface->name = parcMemory_StringDuplicate(name, 64);
+ iface->interfaceIndex = interfaceIndex;
+ iface->loopback = loopback;
+ iface->supportMulticast = supportMulticast;
+ iface->mtu = mtu;
+ iface->addressList = cpiAddressList_Create();
+
+ return iface;
+}
+
+void
+cpiInterface_Destroy(CPIInterface **interfacePtr)
+{
+ assertNotNull(interfacePtr, "Parameter must be non-null double pointer");
+ assertNotNull(*interfacePtr, "Parameter must dereference to non-null pointer");
+
+ CPIInterface *iface = *interfacePtr;
+ parcMemory_Deallocate((void **) &iface->name);
+ cpiAddressList_Destroy(&iface->addressList);
+ parcMemory_Deallocate((void **) &iface);
+ interfacePtr = NULL;
+}
+
+void
+cpiInterface_AddAddress(CPIInterface *iface, CPIAddress *address)
+{
+ assertNotNull(iface, "Parameter iface must be non-null");
+
+ size_t length = cpiAddressList_Length(iface->addressList);
+ for (size_t i = 0; i < length; i++) {
+ const CPIAddress *a = cpiAddressList_GetItem(iface->addressList, i);
+ if (cpiAddress_Equals(a, address)) {
+ return;
+ }
+ }
+
+ cpiAddressList_Append(iface->addressList, address);
+}
+
+const CPIAddressList *
+cpiInterface_GetAddresses(const CPIInterface *iface)
+{
+ assertNotNull(iface, "Parameter iface must be non-null");
+ return iface->addressList;
+}
+
+unsigned
+cpiInterface_GetInterfaceIndex(const CPIInterface *iface)
+{
+ assertNotNull(iface, "Parameter iface must be non-null");
+ return iface->interfaceIndex;
+}
+
+bool
+cpiInterface_NameEquals(const CPIInterface *iface, const char *name)
+{
+ assertNotNull(iface, "Parameter iface must be non-null");
+
+ if (strcasecmp(iface->name, name) == 0) {
+ return true;
+ }
+ return false;
+}
+
+bool
+cpiInterface_Equals(const CPIInterface *a, const CPIInterface *b)
+{
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (a->interfaceIndex == b->interfaceIndex) {
+ if (a->loopback == b->loopback) {
+ if (a->supportMulticast == b->supportMulticast) {
+ if (a->mtu == b->mtu) {
+ if (strcasecmp(a->name, b->name) == 0) {
+ if (cpiAddressList_Equals(a->addressList, b->addressList)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static const char cpi_Iface[] = "Interface";
+static const char cpi_IfName[] = "Name";
+static const char cpi_IFIDX[] = "Index";
+static const char cpi_IsLoopback[] = "Loopback";
+static const char cpi_Multicast[] = "Multicast";
+static const char cpi_MTU[] = "MTU";
+
+static const char cpi_True[] = "true";
+static const char cpi_False[] = "false";
+static const char cpi_Addrs[] = "Addrs";
+
+PARCJSON *
+cpiInterface_ToJson(CPIInterface *iface)
+{
+ assertNotNull(iface, "Parameter must be non-null");
+
+ PARCJSON *inner_json = parcJSON_Create();
+
+ parcJSON_AddString(inner_json, cpi_IfName, iface->name);
+ parcJSON_AddInteger(inner_json, cpi_IFIDX, iface->interfaceIndex);
+ parcJSON_AddString(inner_json, cpi_IsLoopback, iface->loopback ? cpi_True : cpi_False);
+ parcJSON_AddString(inner_json, cpi_Multicast, iface->supportMulticast ? cpi_True : cpi_False);
+ parcJSON_AddInteger(inner_json, cpi_MTU, iface->mtu);
+
+ PARCJSONArray *addrsArray = cpiAddressList_ToJson(iface->addressList);
+ parcJSON_AddArray(inner_json, cpi_Addrs, addrsArray);
+ parcJSONArray_Release(&addrsArray);
+
+ PARCJSON *outter_json = parcJSON_Create();
+ parcJSON_AddObject(outter_json, cpi_Iface, inner_json);
+ parcJSON_Release(&inner_json);
+
+ return outter_json;
+}
+
+CPIInterface *
+cpiInterface_FromJson(PARCJSON *json)
+{
+ assertNotNull(json, "Parameter must be non-null");
+
+
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpi_Iface);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpi_Iface,
+ parcJSON_ToString(json));
+ PARCJSON *ifaceJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(ifaceJson, cpi_IfName);
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ const char *name = parcBuffer_Overlay(sBuf, 0);
+ value = parcJSON_GetValueByName(ifaceJson, cpi_IFIDX);
+ unsigned ifidx = (unsigned) parcJSONValue_GetInteger(value);
+ value = parcJSON_GetValueByName(ifaceJson, cpi_IsLoopback);
+ sBuf = parcJSONValue_GetString(value);
+ const char *loopStr = parcBuffer_Overlay(sBuf, 0);
+ value = parcJSON_GetValueByName(ifaceJson, cpi_Multicast);
+ sBuf = parcJSONValue_GetString(value);
+ const char *mcastStr = parcBuffer_Overlay(sBuf, 0);
+ value = parcJSON_GetValueByName(ifaceJson, cpi_MTU);
+ unsigned mtu = (unsigned) parcJSONValue_GetInteger(value);
+ value = parcJSON_GetValueByName(ifaceJson, cpi_Addrs);
+ PARCJSONArray *addrsJson = parcJSONValue_GetArray(value);
+
+ bool isLoopback = (strcasecmp(loopStr, cpi_True) == 0);
+ bool supportsMulticast = (strcasecmp(mcastStr, cpi_True) == 0);
+
+ CPIInterface *iface = cpiInterface_Create(name, ifidx, isLoopback, supportsMulticast, mtu);
+
+ CPIAddressList *addrs = cpiAddressList_CreateFromJson(addrsJson);
+ for (size_t i = 0; i < cpiAddressList_Length(addrs); i++) {
+ const CPIAddress *addr = cpiAddressList_GetItem(addrs, i);
+ cpiInterface_AddAddress(iface, cpiAddress_Copy(addr));
+ }
+
+ cpiAddressList_Destroy(&addrs);
+ return iface;
+}
+
+const char *
+cpiInterface_GetName(const CPIInterface *iface)
+{
+ assertNotNull(iface, "Parameter iface must be non-null");
+ return iface->name;
+}
+
+unsigned
+cpiInterface_GetMTU(const CPIInterface *iface)
+{
+ assertNotNull(iface, "Parameter iface must be non-null");
+ return iface->mtu;
+}
+
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Interface.h b/libccnx-transport-rta/ccnx/api/control/cpi_Interface.h
new file mode 100644
index 00000000..0ed250b9
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_Interface.h
@@ -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.
+ */
+
+/**
+ * @file cpi_Interface.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_cpi_Interface_h
+#define libccnx_cpi_Interface_h
+
+#include <ccnx/api/control/cpi_Address.h>
+#include <ccnx/api/control/cpi_AddressList.h>
+
+struct cpi_interface;
+typedef struct cpi_interface CPIInterface;
+
+/**
+ * Creates a representation of an interface
+ *
+ * The name is copied. Creates a representation of a system interface.
+ *
+ * @param <#param1#>
+ * @return An allocated object, you must call <code>cpiInterface_Destroy()</code>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIInterface *cpiInterface_Create(const char *name, unsigned interfaceIndex, bool loopback, bool supportMulticast, unsigned mtu);
+
+void cpiInterface_Destroy(CPIInterface **interfacePtr);
+
+/**
+ * Creates an Interface object based on a JSON description.
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return An allocated object, you must call <code>cpiInterface_Destroy()</code>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIInterface *cpiInterface_FromJson(PARCJSON *json);
+
+/**
+ * Creates a JSON description of the object
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return An allocated object, you must destroy it.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *cpiInterface_ToJson(CPIInterface *iface);
+
+/**
+ * Adds an address to an interface
+ *
+ * Does not allow duplicates, if already exists is not added again
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void cpiInterface_AddAddress(CPIInterface *iface, CPIAddress *address);
+
+/**
+ * Retrieves a list of interface addresses
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return Will not be NULL, but may be empty
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const CPIAddressList *cpiInterface_GetAddresses(const CPIInterface *iface);
+
+/**
+ * The interface index
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+unsigned cpiInterface_GetInterfaceIndex(const CPIInterface *iface);
+
+/**
+ * Returns the interface name, e.g. "eth0"
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] iface An allocated CPIInterface
+ *
+ * @return non-null The interface Name as a C-string
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiInterface_GetName(const CPIInterface *iface);
+
+/**
+ * Returns the Maximum Transmission Unit (MTU) of the interface
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] iface An allocated CPIInterface
+ *
+ * @return number The MTU as reported by the kernel
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+unsigned cpiInterface_GetMTU(const CPIInterface *iface);
+
+/**
+ * Determine if two CPIInterfaceName instances are equal.
+ *
+ *
+ * The following equivalence relations on non-null `CPIInterfaceName` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `CPIInterfaceName_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `cpiInterfaceName_Equals(x, y)` must return true if and only if
+ * `cpiInterfaceName_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiInterfaceName_Equals(x, y)` returns true and
+ * `cpiInterfaceName_Equals(y, z)` returns true,
+ * then `cpiInterfaceName_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `cpiInterfaceName_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `cpiInterfaceName_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `CPIInterfaceName` instance.
+ * @param b A pointer to a `CPIInterfaceName` instance.
+ * @return true if the two `CPIInterfaceName` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIInterfaceName *a = cpiInterfaceName_Create();
+ * CPIInterfaceName *b = cpiInterfaceName_Create();
+ *
+ * if (cpiInterfaceName_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool cpiInterface_NameEquals(const CPIInterface *iface, const char *name);
+
+/**
+ * Two CPIInterfaces are idential
+ *
+ * All properties must be the same. The order of addresses matters, and
+ * they must have been added to the address list in the same order.
+ *
+ * The interface name match is case in-sensitive.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool cpiInterface_Equals(const CPIInterface *a, const CPIInterface *b);
+
+/**
+ * <#OneLineDescription#>
+ *
+ * <#Discussion#>
+ *
+ * @param interface A CPIInterface structure pointer.
+ * @return An allocate string representation of the CPIInterface that must be freed via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+char *cpiInterface_ToString(const CPIInterface *interface);
+#endif // libccnx_cpi_Interface_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceEthernet.c b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceEthernet.c
new file mode 100644
index 00000000..e6fb9621
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceEthernet.c
@@ -0,0 +1,183 @@
+/*
+ * 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/api/control/cpi_InterfaceEthernet.h>
+#include <ccnx/api/control/cpi_InterfaceGeneric.h>
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include <string.h>
+
+const static char cpiIFIDX[] = "IFIDX";
+const static char cpiADDRS[] = "ADDRS";
+const static char cpiSTATE[] = "STATE";
+
+static const char *cpiAddEtherConnection = "AddConnEther";
+
+struct cpi_interface_ethernet {
+ CPIInterfaceGeneric *generic;
+};
+
+CPIInterfaceEthernet *
+cpiInterfaceEthernet_Create(unsigned ifidx, CPIAddressList *addresses)
+{
+ assertNotNull(addresses, "Parameter addresses must be non-null");
+
+ CPIInterfaceEthernet *ethernet = parcMemory_AllocateAndClear(sizeof(CPIInterfaceEthernet));
+ assertNotNull(ethernet, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIInterfaceEthernet));
+ ethernet->generic = cpiInterfaceGeneric_Create(ifidx, addresses);
+ return ethernet;
+}
+
+CPIInterfaceEthernet *
+cpiInterfaceEthernet_Copy(const CPIInterfaceEthernet *original)
+{
+ assertNotNull(original, "Parameter original must be non-null");
+
+ CPIInterfaceEthernet *ethernet = parcMemory_AllocateAndClear(sizeof(CPIInterfaceEthernet));
+ assertNotNull(ethernet, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIInterfaceEthernet));
+ ethernet->generic = cpiInterfaceGeneric_Copy(original->generic);
+ return ethernet;
+}
+
+void
+cpiInterfaceEthernet_Destroy(CPIInterfaceEthernet **ethernetPtr)
+{
+ assertNotNull(ethernetPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*ethernetPtr, "Parameter must dereference to non-null pointer");
+
+ CPIInterfaceEthernet *ethernet = *ethernetPtr;
+ cpiInterfaceGeneric_Destroy(&ethernet->generic);
+ parcMemory_Deallocate((void **) &ethernet);
+ *ethernetPtr = NULL;
+}
+
+void
+cpiInterfaceEthernet_SetState(CPIInterfaceEthernet *ethernet, CPIInterfaceStateType state)
+{
+ assertNotNull(ethernet, "Parameter must be non-null pointer");
+ cpiInterfaceGeneric_SetState(ethernet->generic, state);
+}
+
+unsigned
+cpiInterfaceEthernet_GetIndex(const CPIInterfaceEthernet *ethernet)
+{
+ assertNotNull(ethernet, "Parameter must be non-null pointer");
+ return cpiInterfaceGeneric_GetIndex(ethernet->generic);
+}
+
+const CPIAddressList *
+cpiInterfaceEthernet_GetAddresses(const CPIInterfaceEthernet *ethernet)
+{
+ assertNotNull(ethernet, "Parameter must be non-null pointer");
+ return cpiInterfaceGeneric_GetAddresses(ethernet->generic);
+}
+
+CPIInterfaceStateType
+cpiInterfaceEthernet_GetState(const CPIInterfaceEthernet *ethernet)
+{
+ assertNotNull(ethernet, "Parameter must be non-null pointer");
+ return cpiInterfaceGeneric_GetState(ethernet->generic);
+}
+
+PARCJSON *
+cpiInterfaceEthernet_ToJson(const CPIInterfaceEthernet *ethernet)
+{
+ assertNotNull(ethernet, "Parameter must be non-null");
+
+ PARCJSON *innerJson = parcJSON_Create();
+
+ parcJSON_AddInteger(innerJson, cpiIFIDX, cpiInterfaceEthernet_GetIndex(ethernet));
+
+ if (cpiInterfaceEthernet_GetState(ethernet) != CPI_IFACE_UNKNOWN) {
+ parcJSON_AddString(innerJson,
+ cpiSTATE,
+ cpiInterfaceStateType_ToString(cpiInterfaceEthernet_GetState(ethernet)));
+ }
+
+ PARCJSONArray *addrsArray = cpiAddressList_ToJson(cpiInterfaceEthernet_GetAddresses(ethernet));
+ parcJSON_AddArray(innerJson, cpiADDRS, addrsArray);
+ parcJSONArray_Release(&addrsArray);
+
+ PARCJSON *result = parcJSON_Create();
+ parcJSON_AddObject(result, cpiInterfaceType_ToString(CPI_IFACE_ETHERNET), innerJson);
+ parcJSON_Release(&innerJson);
+
+ return result;
+}
+
+CPIInterfaceEthernet *
+cpiInterfaceEthernet_CreateFromJson(PARCJSON *json)
+{
+ assertNotNull(json, "Parameter must be non-null");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpiInterfaceType_ToString(CPI_IFACE_ETHERNET));
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpiInterfaceType_ToString(CPI_IFACE_ETHERNET),
+ parcJSON_ToString(json));
+ PARCJSON *etherJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(etherJson, cpiIFIDX);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpiIFIDX,
+ parcJSON_ToString(json));
+ assertTrue(parcJSONValue_IsNumber(value),
+ "%s is not a number: %s",
+ cpiIFIDX,
+ parcJSON_ToString(json));
+ unsigned ifidx = (unsigned) parcJSONValue_GetInteger(value);
+
+ value = parcJSON_GetValueByName(etherJson, cpiADDRS);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpiADDRS,
+ parcJSON_ToString(json));
+ assertTrue(parcJSONValue_IsArray(value),
+ "%s is not a number: %s",
+ cpiADDRS,
+ parcJSON_ToString(json));
+ PARCJSONArray *addrsJson = parcJSONValue_GetArray(value);
+
+ CPIAddressList *addrs = cpiAddressList_CreateFromJson(addrsJson);
+ CPIInterfaceEthernet *ethernet = cpiInterfaceEthernet_Create(ifidx, addrs);
+
+ value = parcJSON_GetValueByName(etherJson, cpiSTATE);
+ if (value != NULL) {
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ char *state = parcBuffer_Overlay(sBuf, 0);
+ cpiInterfaceEthernet_SetState(ethernet, cpiInterfaceStateType_FromString(state));
+ }
+
+ return ethernet;
+}
+
+bool
+cpiInterfaceEthernet_Equals(const CPIInterfaceEthernet *a, const CPIInterfaceEthernet *b)
+{
+ assertNotNull(a, "Parameter a must be non-null");
+ assertNotNull(b, "Parameter b must be non-null");
+
+ return cpiInterfaceGeneric_Equals(a->generic, b->generic);
+}
+
+const char *
+cpiLinks_AddEtherConnectionJasonTag()
+{
+ return cpiAddEtherConnection;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceEthernet.h b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceEthernet.h
new file mode 100644
index 00000000..11164891
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceEthernet.h
@@ -0,0 +1,243 @@
+/*
+ * 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 cpi_InterfaceEthernet.h
+ * @brief Specialization of InterfaceGeneric to Ethernet
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_cpi_InterfaceEthernet_h
+#define libccnx_cpi_InterfaceEthernet_h
+
+#include <ccnx/api/control/cpi_InterfaceType.h>
+#include <ccnx/api/control/cpi_Address.h>
+#include <ccnx/api/control/cpi_AddressList.h>
+
+
+struct cpi_interface_ethernet;
+typedef struct cpi_interface_ethernet CPIInterfaceEthernet;
+
+/**
+ * Creates an Ethernet-like interface abstraction. Takes ownership of addresses.
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIInterfaceEthernet *cpiInterfaceEthernet_Create(unsigned ifidx, CPIAddressList *addresses);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceEthernet *cpiInterfaceEthernet_Copy(const CPIInterfaceEthernet *ethernet);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void cpiInterfaceEthernet_Destroy(CPIInterfaceEthernet **ethernetPtr);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void cpiInterfaceEthernet_SetState(CPIInterfaceEthernet *ethernet, CPIInterfaceStateType state);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+unsigned cpiInterfaceEthernet_GetIndex(const CPIInterfaceEthernet *ethernet);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const CPIAddressList *cpiInterfaceEthernet_GetAddresses(const CPIInterfaceEthernet *ethernet);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceStateType cpiInterfaceEthernet_GetState(const CPIInterfaceEthernet *ethernet);
+
+/**
+ * Determine if two CPIInterfaceEthernet instances are equal.
+ *
+ * Two CPIInterfaceEthernet instances are equal if, and only if, the same state and index and addresses
+ * are equal in the same order.
+ *
+ * The following equivalence relations on non-null `CPIInterfaceEthernet` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `CPIInterfaceEthernet_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `cpiInterfaceEthernet_Equals(x, y)` must return true if and only if
+ * `cpiInterfaceEthernet_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiInterfaceEthernet_Equals(x, y)` returns true and
+ * `cpiInterfaceEthernet_Equals(y, z)` returns true,
+ * then `cpiInterfaceEthernet_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `cpiInterfaceEthernet_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `cpiInterfaceEthernet_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `CPIInterfaceEthernet` instance.
+ * @param b A pointer to a `CPIInterfaceEthernet` instance.
+ * @return true if the two `CPIInterfaceEthernet` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIInterfaceEthernet *a = cpiInterfaceEthernet_Create();
+ * CPIInterfaceEthernet *b = cpiInterfaceEthernet_Create();
+ *
+ * if (cpiInterfaceEthernet_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool cpiInterfaceEthernet_Equals(const CPIInterfaceEthernet *a, const CPIInterfaceEthernet *b);
+
+/**
+ * JSON representation
+ *
+ * <code>
+ * { "ETHERNET" :
+ * { "IFIDX" : ifidx,
+ * ["STATE" : "UP" | "DOWN", ]
+ * "ADDRS" : [ CPIAddress encodings ]
+ * }
+ * }
+ * </code>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *cpiInterfaceEthernet_ToJson(const CPIInterfaceEthernet *ethernet);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceEthernet *cpiInterfaceEthernet_CreateFromJson(PARCJSON *json);
+#endif // libccnx_cpi_InterfaceEthernet_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceGeneric.c b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceGeneric.c
new file mode 100644
index 00000000..1914dcef
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceGeneric.c
@@ -0,0 +1,127 @@
+/*
+ * 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/api/control/cpi_InterfaceGeneric.h>
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include <string.h>
+
+struct cpi_interface_generic {
+ unsigned ifidx;
+ CPIInterfaceStateType state;
+ CPIAddressList *addresses;
+};
+
+CPIInterfaceGeneric *
+cpiInterfaceGeneric_Create(unsigned ifidx, CPIAddressList *addresses)
+{
+ assertNotNull(addresses, "Parameter addresses must be non-null");
+
+ CPIInterfaceGeneric *generic = parcMemory_AllocateAndClear(sizeof(CPIInterfaceGeneric));
+ assertNotNull(generic, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIInterfaceGeneric));
+ generic->ifidx = ifidx;
+ generic->state = CPI_IFACE_UNKNOWN;
+ generic->addresses = addresses;
+ return generic;
+}
+
+CPIInterfaceGeneric *
+cpiInterfaceGeneric_Copy(const CPIInterfaceGeneric *original)
+{
+ assertNotNull(original, "Parameter original must be non-null");
+
+ CPIInterfaceGeneric *generic = parcMemory_AllocateAndClear(sizeof(CPIInterfaceGeneric));
+ assertNotNull(generic, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIInterfaceGeneric));
+ generic->ifidx = original->ifidx;
+ generic->state = original->state;
+ generic->addresses = cpiAddressList_Copy(original->addresses);
+ return generic;
+}
+
+void
+cpiInterfaceGeneric_Destroy(CPIInterfaceGeneric **genericPtr)
+{
+ assertNotNull(genericPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*genericPtr, "Parameter must dereference to non-null pointer");
+
+ CPIInterfaceGeneric *generic = *genericPtr;
+ cpiAddressList_Destroy(&generic->addresses);
+ parcMemory_Deallocate((void **) &generic);
+ *genericPtr = NULL;
+}
+
+void
+cpiInterfaceGeneric_SetState(CPIInterfaceGeneric *generic, CPIInterfaceStateType state)
+{
+ assertNotNull(generic, "Parameter must be non-null pointer");
+ generic->state = state;
+}
+
+unsigned
+cpiInterfaceGeneric_GetIndex(const CPIInterfaceGeneric *generic)
+{
+ assertNotNull(generic, "Parameter must be non-null pointer");
+ return generic->ifidx;
+}
+
+const CPIAddressList *
+cpiInterfaceGeneric_GetAddresses(const CPIInterfaceGeneric *generic)
+{
+ assertNotNull(generic, "Parameter must be non-null pointer");
+ return generic->addresses;
+}
+
+CPIInterfaceStateType
+cpiInterfaceGeneric_GetState(const CPIInterfaceGeneric *generic)
+{
+ assertNotNull(generic, "Parameter must be non-null pointer");
+ return generic->state;
+}
+
+bool
+cpiInterfaceGeneric_Equals(const CPIInterfaceGeneric *a, const CPIInterfaceGeneric *b)
+{
+ assertNotNull(a, "Parameter a must be non-null");
+ assertNotNull(b, "Parameter b must be non-null");
+
+ if (a == b) {
+ return true;
+ }
+
+ if (a->ifidx == b->ifidx) {
+ if (a->state == b->state) {
+ if (cpiAddressList_Equals(a->addresses, b->addresses)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+PARCBufferComposer *
+cpiInterfaceGeneric_BuildString(const CPIInterfaceGeneric *interface, PARCBufferComposer *composer)
+{
+ char *addressString = cpiAddressList_ToString(interface->addresses);
+ parcBufferComposer_Format(composer, "%5d %4s %s",
+ interface->ifidx,
+ cpiInterfaceStateType_ToString(interface->state),
+ addressString
+ );
+ parcMemory_Deallocate((void **) &addressString);
+ return composer;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceGeneric.h b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceGeneric.h
new file mode 100644
index 00000000..ffdd0978
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceGeneric.h
@@ -0,0 +1,219 @@
+/*
+ * 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 cpi_InterfaceGeneric.h
+ * @brief A generic interface that is used as a super type for other interfaces.
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_cpi_InterfaceGeneric_h
+#define libccnx_cpi_InterfaceGeneric_h
+
+#include <ccnx/api/control/cpi_InterfaceType.h>
+#include <ccnx/api/control/cpi_Address.h>
+#include <ccnx/api/control/cpi_AddressList.h>
+
+
+struct cpi_interface_generic;
+typedef struct cpi_interface_generic CPIInterfaceGeneric;
+
+/**
+ * Creates an Generic-like interface abstraction. Takes ownership of addresses.
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIInterfaceGeneric *cpiInterfaceGeneric_Create(unsigned ifidx, CPIAddressList *addresses);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceGeneric *cpiInterfaceGeneric_Copy(const CPIInterfaceGeneric *generic);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void cpiInterfaceGeneric_Destroy(CPIInterfaceGeneric **genericPtr);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void cpiInterfaceGeneric_SetState(CPIInterfaceGeneric *generic, CPIInterfaceStateType state);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+unsigned cpiInterfaceGeneric_GetIndex(const CPIInterfaceGeneric *generic);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const CPIAddressList *cpiInterfaceGeneric_GetAddresses(const CPIInterfaceGeneric *generic);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceStateType cpiInterfaceGeneric_GetState(const CPIInterfaceGeneric *generic);
+
+/**
+ * Determine if two CPIInterfaceGeneric instances are equal.
+ *
+ * Two CPIInterfaceGeneric instances are equal if, and only if, the same state and index and addresses
+ * are equal in the same order.
+ *
+ * The following equivalence relations on non-null `CPIInterfaceGeneric` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `CPIInterfaceGeneric_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `cpiInterfaceGeneric_Equals(x, y)` must return true if and only if
+ * `cpiInterfaceGeneric_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiInterfaceGeneric_Equals(x, y)` returns true and
+ * `cpiInterfaceGeneric_Equals(y, z)` returns true,
+ * then `cpiInterfaceGeneric_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `cpiInterfaceGeneric_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `cpiInterfaceGeneric_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `CPIInterfaceGeneric` instance.
+ * @param b A pointer to a `CPIInterfaceGeneric` instance.
+ * @return true if the two `CPIInterfaceGeneric` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIInterfaceGeneric *a = cpiInterfaceGeneric_Create();
+ * CPIInterfaceGeneric *b = cpiInterfaceGeneric_Create();
+ *
+ * if (cpiInterfaceGeneric_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool cpiInterfaceGeneric_Equals(const CPIInterfaceGeneric *a, const CPIInterfaceGeneric *b);
+
+/**
+ * <#OneLineDescription#>
+ *
+ * <#Discussion#>
+ *
+ * @param [in] interface
+ * @param [in] composer A pointer to a PARCBufferComposer instance.
+ * @return return The input parameter string.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *cpiInterfaceGeneric_BuildString(const CPIInterfaceGeneric *interface, PARCBufferComposer *composer);
+#endif // libccnx_cpi_InterfaceGeneric_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPMulticast.h b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPMulticast.h
new file mode 100644
index 00000000..b218a407
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPMulticast.h
@@ -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.
+ */
+
+/**
+ * @file cpi_InterfaceIPMulticast.h
+ * @brief UDP Multicast overlay
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_cpi_InterfaceIPMulticast_h
+#define libccnx_cpi_InterfaceIPMulticast_h
+
+#include <ccnx/api/control/cpi_InterfaceType.h>
+#include <ccnx/api/control/cpi_Address.h>
+
+struct cpi_interface_ipmcast;
+/**
+ *
+ * @see cpiInterfaceIPMulticast_Create
+ */
+typedef struct cpi_interface_ipmcast CPIInterfaceIPMulticast;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceIPMulticast *cpiInterfaceIPMulticast_Create(unsigned ifidx, CPIInterfaceStateType state, CPIAddress *source, CPIAddress *group, IPTunnelType tunnelType);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceIPMulticast *cpiInterfaceIPMulticast_Copy(const CPIInterfaceIPMulticast *ipmcast);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void cpiInterfaceIPMulticast_Destroy(CPIInterfaceIPMulticast **ipmcastPtr);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+unsigned cpiInterfaceIPMulticast_GetIndex(const CPIInterfaceIPMulticast *ipmcast);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const CPIAddress *cpiInterfaceIPMulticast_GetSourceAddress(const CPIInterfaceIPMulticast *ipmcast);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const CPIAddress *cpiInterfaceIPMulticast_GetGroupAddress(const CPIInterfaceIPMulticast *ipmcast);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+IPTunnelType cpiInterfaceIPMulticast_GetTunnelType(const CPIInterfaceIPMulticast *ipmcast);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceStateType cpiInterfaceIPMulticast_GetState(const CPIInterfaceIPMulticast *ipmcast);
+#endif // libccnx_cpi_InterfaceIPMulticast_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnel.c b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnel.c
new file mode 100644
index 00000000..92f77a29
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnel.c
@@ -0,0 +1,331 @@
+/*
+ * 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_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_JSON.h>
+
+#include <ccnx/api/control/cpi_InterfaceIPTunnel.h>
+#include <ccnx/api/control/cpi_InterfaceGeneric.h>
+
+#define SOURCE_INDEX 0
+#define DESTINATION_INDEX 1
+
+const static char cpiIFIDX[] = "IFIDX";
+const static char cpiSRCADDR[] = "SRC";
+const static char cpiDSTADDR[] = "DST";
+const static char cpiTUNTYPE[] = "TUNTYPE";
+const static char cpiSTATE[] = "STATE";
+const static char cpiSYMBOLIC[] = "SYMBOLIC";
+
+struct cpi_interface_iptun {
+ CPIInterfaceGeneric *generic;
+ CPIInterfaceIPTunnelType tunnelType;
+ char *symbolic;
+};
+
+struct iptunnel_type_string_s {
+ CPIInterfaceIPTunnelType type;
+ const char *str;
+} iptunnelTypeStrings[] = {
+ { .type = IPTUN_UDP, .str = "UDP" },
+ { .type = IPTUN_TCP, .str = "TCP" },
+ { .type = IPTUN_GRE, .str = "GRE" },
+ { .type = 0, .str = NULL },
+};
+
+
+static void
+_cpiInterfaceIPTunnel_Destroy(CPIInterfaceIPTunnel **iptunPtr)
+{
+ assertNotNull(iptunPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*iptunPtr, "Parameter must dereference to non-null pointer");
+
+ CPIInterfaceIPTunnel *iptun = *iptunPtr;
+ cpiInterfaceGeneric_Destroy(&iptun->generic);
+ parcMemory_Deallocate((void **) &iptun->symbolic);
+}
+
+parcObject_ExtendPARCObject(CPIInterfaceIPTunnel, _cpiInterfaceIPTunnel_Destroy, cpiInterfaceIPTunnel_Copy, NULL, cpiInterfaceIPTunnel_Equals, NULL, NULL, cpiInterfaceIPTunnel_ToJson);
+
+parcObject_ImplementRelease(cpiInterfaceIPTunnel, CPIInterfaceIPTunnel);
+
+parcObject_ImplementAcquire(cpiInterfaceIPTunnel, CPIInterfaceIPTunnel);
+
+const char *
+cpiInterfaceIPTunnel_TypeToString(CPIInterfaceIPTunnelType type)
+{
+ for (int i = 0; iptunnelTypeStrings[i].str != NULL; i++) {
+ if (iptunnelTypeStrings[i].type == type) {
+ return iptunnelTypeStrings[i].str;
+ }
+ }
+ assertTrue(0, "Unknown type: %d", type);
+ abort();
+}
+
+CPIInterfaceIPTunnelType
+cpiInterfaceIPTunnel_TypeFromString(const char *str)
+{
+ for (int i = 0; iptunnelTypeStrings[i].str != NULL; i++) {
+ if (strcasecmp(iptunnelTypeStrings[i].str, str) == 0) {
+ return iptunnelTypeStrings[i].type;
+ }
+ }
+ assertTrue(0, "Unknown stirng: %s", str);
+ abort();
+}
+
+CPIInterfaceIPTunnel *
+cpiInterfaceIPTunnel_Create(unsigned ifidx, CPIAddress *source, CPIAddress *destination, CPIInterfaceIPTunnelType tunnelType, const char *symbolic)
+{
+ assertNotNull(source, "Parameter source must be non-null");
+ assertNotNull(destination, "Parameter destination must be non-null");
+
+ assertTrue(cpiAddress_GetType(source) == cpiAddressType_INET || cpiAddress_GetType(source) == cpiAddressType_INET6,
+ "source address unsupported type: %d",
+ cpiAddress_GetType(source));
+
+ assertTrue(cpiAddress_GetType(destination) == cpiAddressType_INET || cpiAddress_GetType(destination) == cpiAddressType_INET6,
+ "destination address unsupported type: %d",
+ cpiAddress_GetType(destination));
+
+ CPIInterfaceIPTunnel *iptun = parcObject_CreateInstance(CPIInterfaceIPTunnel);
+ assertNotNull(iptun, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIInterfaceIPTunnel));
+
+ CPIAddressList *addrlist = cpiAddressList_Create();
+ cpiAddressList_Append(addrlist, source);
+ cpiAddressList_Append(addrlist, destination);
+
+ iptun->generic = cpiInterfaceGeneric_Create(ifidx, addrlist);
+ iptun->tunnelType = tunnelType;
+ iptun->symbolic = parcMemory_StringDuplicate(symbolic, strlen(symbolic));
+
+ return iptun;
+}
+
+CPIInterfaceIPTunnel *
+cpiInterfaceIPTunnel_Copy(const CPIInterfaceIPTunnel *original)
+{
+ assertNotNull(original, "Parameter original must be non-null");
+ CPIInterfaceIPTunnel *iptun = parcObject_CreateInstance(CPIInterfaceIPTunnel);
+ assertNotNull(iptun, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIInterfaceIPTunnel));
+ iptun->generic = cpiInterfaceGeneric_Copy(original->generic);
+ iptun->tunnelType = original->tunnelType;
+ iptun->symbolic = parcMemory_StringDuplicate(original->symbolic, strlen(original->symbolic));
+ return iptun;
+}
+
+void
+cpiInterfaceIPTunnel_SetState(CPIInterfaceIPTunnel *iptun, CPIInterfaceStateType state)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+ cpiInterfaceGeneric_SetState(iptun->generic, state);
+}
+
+const char *
+cpiInterfaceIPTunnel_GetSymbolicName(const CPIInterfaceIPTunnel *iptun)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+ return iptun->symbolic;
+}
+
+unsigned
+cpiInterfaceIPTunnel_GetIndex(const CPIInterfaceIPTunnel *iptun)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+ return cpiInterfaceGeneric_GetIndex(iptun->generic);
+}
+
+const CPIAddress *
+cpiInterfaceIPTunnel_GetSourceAddress(const CPIInterfaceIPTunnel *iptun)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+ const CPIAddressList *addrs = cpiInterfaceGeneric_GetAddresses(iptun->generic);
+ return cpiAddressList_GetItem(addrs, SOURCE_INDEX);
+}
+
+const CPIAddress *
+cpiInterfaceIPTunnel_GetDestinationAddress(const CPIInterfaceIPTunnel *iptun)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+ const CPIAddressList *addrs = cpiInterfaceGeneric_GetAddresses(iptun->generic);
+ return cpiAddressList_GetItem(addrs, DESTINATION_INDEX);
+}
+
+CPIInterfaceIPTunnelType
+cpiInterfaceIPTunnel_GetTunnelType(const CPIInterfaceIPTunnel *iptun)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+ return iptun->tunnelType;
+}
+
+CPIInterfaceStateType
+cpiInterfaceIPTunnel_GetState(const CPIInterfaceIPTunnel *iptun)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+ return cpiInterfaceGeneric_GetState(iptun->generic);
+}
+
+bool
+cpiInterfaceIPTunnel_Equals(const CPIInterfaceIPTunnel *a, const CPIInterfaceIPTunnel *b)
+{
+ assertNotNull(a, "Parameter a must be non-null");
+ assertNotNull(b, "Parameter b must be non-null");
+
+ if (a->tunnelType == b->tunnelType) {
+ if (cpiInterfaceGeneric_Equals(a->generic, b->generic)) {
+ if (strcasecmp(a->symbolic, b->symbolic) == 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * JSON representation
+ *
+ * <code>
+ * { "TUNNEL" :
+ * { "IFIDX" : ifidx,
+ * "SYMBOLIC" : "tun3",
+ * ["STATE" : "UP" | "DOWN", ]
+ * "TYPE": "UDP" | "TCP" | "GRE",
+ * "SRC" : {srcaddr},
+ * "DST" : {dstaddr}
+ * }
+ * }
+ * </code>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *
+cpiInterfaceIPTunnel_ToJson(const CPIInterfaceIPTunnel *iptun)
+{
+ assertNotNull(iptun, "Parameter must be non-null");
+
+ PARCJSON *inner_json = parcJSON_Create();
+
+ parcJSON_AddInteger(inner_json, cpiIFIDX, cpiInterfaceIPTunnel_GetIndex(iptun));
+ parcJSON_AddString(inner_json, cpiSYMBOLIC, iptun->symbolic);
+
+ if (cpiInterfaceIPTunnel_GetState(iptun) != CPI_IFACE_UNKNOWN) {
+ parcJSON_AddString(inner_json, cpiSTATE, cpiInterfaceStateType_ToString(cpiInterfaceIPTunnel_GetState(iptun)));
+ }
+ parcJSON_AddString(inner_json, cpiTUNTYPE, cpiInterfaceIPTunnel_TypeToString(cpiInterfaceIPTunnel_GetTunnelType(iptun)));
+
+ PARCJSON *json = cpiAddress_ToJson(cpiInterfaceIPTunnel_GetSourceAddress(iptun));
+ parcJSON_AddObject(inner_json, cpiSRCADDR, json);
+ parcJSON_Release(&json);
+
+ json = cpiAddress_ToJson(cpiInterfaceIPTunnel_GetDestinationAddress(iptun));
+ parcJSON_AddObject(inner_json, cpiDSTADDR, json);
+ parcJSON_Release(&json);
+
+ PARCJSON *outter_json = parcJSON_Create();
+ parcJSON_AddObject(outter_json, cpiInterfaceType_ToString(CPI_IFACE_TUNNEL), inner_json);
+ parcJSON_Release(&inner_json);
+
+ return outter_json;
+}
+
+CPIInterfaceIPTunnel *
+cpiInterfaceIPTunnel_CreateFromJson(PARCJSON *json)
+{
+ assertNotNull(json, "Parameter must be non-null");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpiInterfaceType_ToString(CPI_IFACE_TUNNEL));
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpiInterfaceType_ToString(CPI_IFACE_TUNNEL),
+ parcJSON_ToString(json));
+ PARCObject *tunnelJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(tunnelJson, cpiIFIDX);
+ assertNotNull(value, "Could not find key %s: %s", cpiIFIDX, parcJSON_ToString(json));
+ assertTrue(parcJSONValue_IsNumber(value),
+ "%s is not a number: %s",
+ cpiIFIDX,
+ parcJSON_ToString(json));
+ PARCJSONValue *ifidx_value = value;
+
+ value = parcJSON_GetValueByName(tunnelJson, cpiSYMBOLIC);
+ assertNotNull(value, "Could not find key %s: %s", cpiSYMBOLIC, parcJSON_ToString(json));
+ assertTrue(parcJSONValue_IsString(value),
+ "%s is not a string: %s",
+ cpiSYMBOLIC,
+ parcJSON_ToString(json));
+ PARCJSONValue *symbolic_value = value;
+
+ value = parcJSON_GetValueByName(tunnelJson, cpiTUNTYPE);
+ assertNotNull(value, "Could not find key %s: %s", cpiTUNTYPE, parcJSON_ToString(json));
+ assertTrue(parcJSONValue_IsString(value),
+ "%s is not a number: %s",
+ cpiTUNTYPE,
+ parcJSON_ToString(json));
+ PARCJSONValue *tuntype_value = value;
+
+ value = parcJSON_GetValueByName(tunnelJson, cpiSRCADDR);
+ assertNotNull(value, "Could not find key %s: %s", cpiSRCADDR, parcJSON_ToString(json));
+ assertTrue(parcJSONValue_IsJSON(value),
+ "%s is not an array: %s",
+ cpiSRCADDR,
+ parcJSON_ToString(json));
+ PARCJSONValue *srcaddr_value = value;
+
+ value = parcJSON_GetValueByName(tunnelJson, cpiDSTADDR);
+ assertNotNull(value, "Could not find key %s: %s", cpiDSTADDR, parcJSON_ToString(json));
+ assertTrue(parcJSONValue_IsJSON(value),
+ "%s is not an array: %s",
+ cpiDSTADDR,
+ parcJSON_ToString(json));
+ PARCJSONValue *dstaddr_value = value;
+
+ unsigned ifidx = (unsigned) parcJSONValue_GetInteger(ifidx_value);
+ PARCBuffer *sBuf = parcJSONValue_GetString(symbolic_value);
+ const char *symbolic = parcBuffer_Overlay(sBuf, 0);
+ CPIAddress *srcaddr =
+ cpiAddress_CreateFromJson(parcJSONValue_GetJSON(srcaddr_value));
+ CPIAddress *dstaddr =
+ cpiAddress_CreateFromJson(parcJSONValue_GetJSON(dstaddr_value));
+ sBuf = parcJSONValue_GetString(tuntype_value);
+ CPIInterfaceIPTunnelType tunnelType =
+ cpiInterfaceIPTunnel_TypeFromString(parcBuffer_Overlay(sBuf, 0));
+
+ CPIInterfaceIPTunnel *iptun =
+ cpiInterfaceIPTunnel_Create(ifidx, srcaddr, dstaddr, tunnelType, symbolic);
+
+ PARCJSONValue *state_value = parcJSON_GetValueByName(tunnelJson, cpiSTATE);
+ if (state_value != NULL) {
+ sBuf = parcJSONValue_GetString(state_value);
+ cpiInterfaceIPTunnel_SetState(iptun, cpiInterfaceStateType_FromString(parcBuffer_Overlay(sBuf, 0)));
+ }
+
+ return iptun;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnel.h b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnel.h
new file mode 100644
index 00000000..e5a01a18
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnel.h
@@ -0,0 +1,349 @@
+/*
+ * 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 cpi_InterfaceIPTunnel.h
+ * @brief Represents a point-to-point tunnel over IP.
+ *
+ * The carries can be UDP, TCP, or GRE
+ *
+ * We use InterfaceGeneric to back this type. We always use 2 addresses in the address list.
+ * Address 0 is the source and address 1 is the destination.
+ *
+ */
+#ifndef libccnx_cpi_InterfaceIPTunnel_h
+#define libccnx_cpi_InterfaceIPTunnel_h
+
+#include <ccnx/api/control/cpi_InterfaceType.h>
+#include <ccnx/api/control/cpi_Address.h>
+
+#include <parc/algol/parc_JSON.h>
+
+struct cpi_interface_iptun;
+/**
+ *
+ * @see cpiInterfaceIPTunnel_Create
+ */
+typedef struct cpi_interface_iptun CPIInterfaceIPTunnel;
+
+typedef enum {
+ IPTUN_UDP,
+ IPTUN_TCP,
+ IPTUN_GRE
+} CPIInterfaceIPTunnelType;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] type A CPIInterfaceIPTunnelType value
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const char *cpiInterfaceIPTunnel_TypeToString(CPIInterfaceIPTunnelType type);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] str A nul-terminated C string.
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceIPTunnelType cpiInterfaceIPTunnel_TypeFromString(const char *str);
+
+/**
+ * Creates a representation of an IP tunnel
+ *
+ * The symblic name will be used in the future to refer to this tunnel. It must be unique or the forwarder will reject the command.
+ *
+ * @param [in] ifidx The interface index of the tunnel (may be 0 if not known)
+ * @param [in] source The local address and optional port
+ * @param [in] destination The remote address and port
+ * @param [in] tunnelType The encapsulation protocol
+ * @param [in] symbolic The symbolic name to refer to this tunnel (e.g. 'tun2')
+ *
+ * @return non-null An allocated CPIInterfaceIPTunnel
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceIPTunnel *cpiInterfaceIPTunnel_Create(unsigned ifidx, CPIAddress *source, CPIAddress *destination, CPIInterfaceIPTunnelType tunnelType, const char *symbolic);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] ipTunnel A pointer to a valid CPIInterfaceIPTunnel
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceIPTunnel *cpiInterfaceIPTunnel_Copy(const CPIInterfaceIPTunnel *ipTunnel);
+CPIInterfaceIPTunnel *cpiInterfaceIPTunnel_Acquire(const CPIInterfaceIPTunnel *ipTunnel);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] ipTunnel A pointer to a valid CPIInterfaceIPTunnel
+ * @param [in] state A CPIInterfaceStateType value.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void cpiInterfaceIPTunnel_SetState(CPIInterfaceIPTunnel *ipTunnel, CPIInterfaceStateType state);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] ipTunnelPtr A pointer to a pointer to a valid CPIInterfaceIPTunnel instance.
+ *
+ * @see <#references#>
+ */
+void cpiInterfaceIPTunnel_Release(CPIInterfaceIPTunnel **ipTunnelPtr);
+
+/**
+ * Returns the symbolic name of the tunnel
+ *
+ * The caller should make a copy of the string if it will be stored.
+ *
+ * @param [in] ipTunnel A pointer to a valid CPIInterfaceIPTunnel
+ *
+ * @return non-null The symbolic name
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const char *cpiInterfaceIPTunnel_GetSymbolicName(const CPIInterfaceIPTunnel *ipTunnel);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] ipTunnel A pointer to a valid CPIInterfaceIPTunnel
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+unsigned cpiInterfaceIPTunnel_GetIndex(const CPIInterfaceIPTunnel *ipTunnel);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] ipTunnel A pointer to a valid CPIInterfaceIPTunnel
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const CPIAddress *cpiInterfaceIPTunnel_GetSourceAddress(const CPIInterfaceIPTunnel *ipTunnel);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] ipTunnel A pointer to a valid CPIInterfaceIPTunnel
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const CPIAddress *cpiInterfaceIPTunnel_GetDestinationAddress(const CPIInterfaceIPTunnel *ipTunnel);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] ipTunnel A pointer to a valid CPIInterfaceIPTunnel
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceIPTunnelType cpiInterfaceIPTunnel_GetTunnelType(const CPIInterfaceIPTunnel *ipTunnel);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] ipTunnel A pointer to a valid CPIInterfaceIPTunnel
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceStateType cpiInterfaceIPTunnel_GetState(const CPIInterfaceIPTunnel *ipTunnel);
+
+/**
+ * Determine if two CPIInterfaceIPTunnel instances are equal.
+ *
+ *
+ * The following equivalence relations on non-null `CPIInterfaceIPTunnel` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `CPIInterfaceIPTunnel_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `cpiInterfaceIPTunnel_Equals(x, y)` must return true if and only if
+ * `cpiInterfaceIPTunnel_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiInterfaceIPTunnel_Equals(x, y)` returns true and
+ * `cpiInterfaceIPTunnel_Equals(y, z)` returns true,
+ * then `cpiInterfaceIPTunnel_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `cpiInterfaceIPTunnel_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `cpiInterfaceIPTunnel_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `CPIInterfaceIPTunnel` instance.
+ * @param b A pointer to a `CPIInterfaceIPTunnel` instance.
+ * @return true if the two `CPIInterfaceIPTunnel` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIInterfaceIPTunnel *a = cpiInterfaceIPTunnel_Create();
+ * CPIInterfaceIPTunnel *b = cpiInterfaceIPTunnel_Create();
+ *
+ * if (cpiInterfaceIPTunnel_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool cpiInterfaceIPTunnel_Equals(const CPIInterfaceIPTunnel *a, const CPIInterfaceIPTunnel *b);
+
+/**
+ * JSON representation
+ *
+ * <code>
+ * { "TUNNEL" :
+ * { "IFIDX" : ifidx,
+ * ["STATE" : "UP" | "DOWN", ]
+ * "TYPE": "UDP" | "TCP" | "GRE",
+ * "SRC" : {srcaddr},
+ * "DST" : {dstaddr}
+ * }
+ * }
+ * </code>
+ *
+ * @param [in] ipTunnel A pointer to a valid CPIInterfaceIPTunnel
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *cpiInterfaceIPTunnel_ToJson(const CPIInterfaceIPTunnel *ipTunnel);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] json A pointer to a valid PARCJSON instance.
+ *
+ * @return non-NULL A pointer to a valid CPIInterfaceIPTunnel instance.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceIPTunnel *cpiInterfaceIPTunnel_CreateFromJson(PARCJSON *json);
+#endif // libccnx_cpi_InterfaceIPTunnel_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnelList.c b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnelList.c
new file mode 100644
index 00000000..7515258d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnelList.c
@@ -0,0 +1,159 @@
+/*
+ * 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_ArrayList.h>
+
+#include <ccnx/api/control/cpi_InterfaceIPTunnelList.h>
+#include <LongBow/runtime.h>
+
+struct cpi_interface_iptunnel_list {
+ PARCArrayList *listOfTunnels;
+};
+
+/**
+ * PARCArrayList entry destroyer
+ */
+static void
+_arrayDestroyer(void **voidPtr)
+{
+ CPIInterfaceIPTunnel **entryPtr = (CPIInterfaceIPTunnel **) voidPtr;
+ cpiInterfaceIPTunnel_Release(entryPtr);
+}
+
+CPIInterfaceIPTunnelList *
+cpiInterfaceIPTunnelList_Create(void)
+{
+ CPIInterfaceIPTunnelList *list = parcMemory_AllocateAndClear(sizeof(CPIInterfaceIPTunnelList));
+ assertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIInterfaceIPTunnelList));
+ list->listOfTunnels = parcArrayList_Create(_arrayDestroyer);
+ return list;
+}
+
+void
+cpiInterfaceIPTunnelList_Destroy(CPIInterfaceIPTunnelList **listPtr)
+{
+ assertNotNull(listPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*listPtr, "Parameter must dereference to non-null pointer");
+ CPIInterfaceIPTunnelList *list = *listPtr;
+ parcArrayList_Destroy(&list->listOfTunnels);
+ parcMemory_Deallocate((void **) &list);
+ *listPtr = NULL;
+}
+
+void
+cpiInterfaceIPTunnelList_Append(CPIInterfaceIPTunnelList *list, CPIInterfaceIPTunnel *entry)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ assertNotNull(entry, "Parameter entry must be non-null");
+
+ parcArrayList_Add(list->listOfTunnels, (PARCObject *) entry);
+}
+
+size_t
+cpiInterfaceIPTunnelList_Length(const CPIInterfaceIPTunnelList *list)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ return parcArrayList_Size(list->listOfTunnels);
+}
+
+CPIInterfaceIPTunnel *
+cpiInterfaceIPTunnelList_Get(CPIInterfaceIPTunnelList *list, size_t index)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ CPIInterfaceIPTunnel *original = (CPIInterfaceIPTunnel *) parcArrayList_Get(list->listOfTunnels, index);
+ return cpiInterfaceIPTunnel_Copy(original);
+}
+
+bool
+cpiInterfaceIPTunnelList_Equals(const CPIInterfaceIPTunnelList *a, const CPIInterfaceIPTunnelList *b)
+{
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (parcArrayList_Size(a->listOfTunnels) == parcArrayList_Size(b->listOfTunnels)) {
+ size_t length = parcArrayList_Size(a->listOfTunnels);
+ for (size_t i = 0; i < length; i++) {
+ CPIInterfaceIPTunnel *tunnel_a = (CPIInterfaceIPTunnel *) parcArrayList_Get(a->listOfTunnels, i);
+ CPIInterfaceIPTunnel *tunnel_b = (CPIInterfaceIPTunnel *) parcArrayList_Get(b->listOfTunnels, i);
+ if (!cpiInterfaceIPTunnel_Equals(tunnel_a, tunnel_b)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+const char cpi_InterfaceIPTunnelList[] = "TunnelList";
+
+PARCJSON *
+cpiInterfaceIPTunnelList_ToJson(const CPIInterfaceIPTunnelList *list)
+{
+ assertNotNull(list, "Parameter must be non-null");
+
+ PARCJSONArray *tunnelList = parcJSONArray_Create();
+
+ size_t length = parcArrayList_Size(list->listOfTunnels);
+ for (size_t i = 0; i < length; i++) {
+ CPIInterfaceIPTunnel *tunnel = (CPIInterfaceIPTunnel *) parcArrayList_Get(list->listOfTunnels, i);
+ PARCJSON *json = cpiInterfaceIPTunnel_ToJson(tunnel);
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ parcJSON_Release(&json);
+ parcJSONArray_AddValue(tunnelList, value);
+ parcJSONValue_Release(&value);
+ }
+
+ PARCJSON *result = parcJSON_Create();
+ parcJSON_AddArray(result, cpi_InterfaceIPTunnelList, tunnelList);
+ parcJSONArray_Release(&tunnelList);
+
+ return result;
+}
+
+CPIInterfaceIPTunnelList *
+cpiInterfaceIPTunnelList_FromJson(PARCJSON *json)
+{
+ assertNotNull(json, "Parameter must be non-null");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpi_InterfaceIPTunnelList);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpi_InterfaceIPTunnelList,
+ parcJSON_ToString(json));
+ PARCJSONArray *tunnelListJson = parcJSONValue_GetArray(value);
+
+ CPIInterfaceIPTunnelList *list = cpiInterfaceIPTunnelList_Create();
+
+ size_t length = parcJSONArray_GetLength(tunnelListJson);
+ for (size_t i = 0; i < length; i++) {
+ value = parcJSONArray_GetValue(tunnelListJson, i);
+ CPIInterfaceIPTunnel *tunnel =
+ cpiInterfaceIPTunnel_CreateFromJson(parcJSONValue_GetJSON(value));
+
+ cpiInterfaceIPTunnelList_Append(list, tunnel);
+ }
+
+ return list;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnelList.h b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnelList.h
new file mode 100644
index 00000000..e9ec80bf
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceIPTunnelList.h
@@ -0,0 +1,204 @@
+/*
+ * 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 cpi_InterfaceIPTunnelList.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_cpi_InterfaceIPTunnelList_h
+#define libccnx_cpi_InterfaceIPTunnelList_h
+
+struct cpi_interface_iptunnel_list;
+typedef struct cpi_interface_iptunnel_list CPIInterfaceIPTunnelList;
+
+#include <ccnx/api/control/cpi_InterfaceIPTunnel.h>
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceIPTunnelList *cpiInterfaceIPTunnelList_Create(void);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void cpiInterfaceIPTunnelList_Destroy(CPIInterfaceIPTunnelList **listPtr);
+
+/**
+ * Adds a iptunnel entry to the list.
+ *
+ * Appends <code>entry</code> to the list. Takes ownership of the entry
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void cpiInterfaceIPTunnelList_Append(CPIInterfaceIPTunnelList *list, CPIInterfaceIPTunnel *entry);
+
+/**
+ * Determine if two CPIInterfaceIPTunnelList instances are equal.
+ *
+ * Two CPIInterfaceIPTunnelList instances are equal if, and only if,
+ * the size of the lists are equal and every element is equal and in the same order.
+ *
+ * The following equivalence relations on non-null `CPIInterfaceIPTunnelList` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `CPIInterfaceIPTunnelList_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `cpiInterfaceIPTunnelList_Equals(x, y)` must return true if and only if
+ * `cpiInterfaceIPTunnelList_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiInterfaceIPTunnelList_Equals(x, y)` returns true and
+ * `cpiInterfaceIPTunnelList_Equals(y, z)` returns true,
+ * then `cpiInterfaceIPTunnelList_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `cpiInterfaceIPTunnelList_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `cpiInterfaceIPTunnelList_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `CPIInterfaceIPTunnelList` instance.
+ * @param b A pointer to a `CPIInterfaceIPTunnelList` instance.
+ * @return true if the two `CPIInterfaceIPTunnelList` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIInterfaceIPTunnelList *a = cpiInterfaceIPTunnelList_Create();
+ * CPIInterfaceIPTunnelList *b = cpiInterfaceIPTunnelList_Create();
+ *
+ * if (cpiInterfaceIPTunnelList_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool cpiInterfaceIPTunnelList_Equals(const CPIInterfaceIPTunnelList *a, const CPIInterfaceIPTunnelList *b);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+size_t cpiInterfaceIPTunnelList_Length(const CPIInterfaceIPTunnelList *list);
+
+/**
+ * Returns a reference counted copy of the iptunnel entry.
+ *
+ * Caller must destroy the returned value.
+ * Will assert if you go beyond the end of the list.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIInterfaceIPTunnel *cpiInterfaceIPTunnelList_Get(CPIInterfaceIPTunnelList *list, size_t index);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *cpiInterfaceIPTunnelList_ToJson(const CPIInterfaceIPTunnelList *list);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceIPTunnelList *cpiInterfaceIPTunnelList_FromJson(PARCJSON *json);
+#endif // libccnx_cpi_InterfaceIPTunnelList_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceL2Group.h b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceL2Group.h
new file mode 100644
index 00000000..2104c430
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceL2Group.h
@@ -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.
+ */
+
+/**
+ * @file cpi_InterfaceL2Group.h
+ * @brief Layer 2 group address overlay
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_cpi_InterfaceL2Group_h
+#define libccnx_cpi_InterfaceL2Group_h
+
+#include <ccnx/api/control/cpi_InterfaceType.h>
+#include <ccnx/api/control/cpi_Address.h>
+
+struct cpi_interface_l2group;
+/**
+ *
+ * @see cpiInterfaceL2Group_Create
+ */
+typedef struct cpi_interface_l2group CPIInterfaceL2Group;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceL2Group *cpiInterfaceL2Group_Create(unsigned ifidx, CPIInterfaceStateType state, CPIAddress *source, CPIAddress *group, IPTunnelType tunnelType);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceL2Group *cpiInterfaceL2Group_Copy(const CPIInterfaceL2Group *l2group);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void cpiInterfaceL2Group_Destroy(CPIInterfaceL2Group **l2groupPtr);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+unsigned cpiInterfaceL2Group_GetIndex(const CPIInterfaceL2Group *l2group);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const CPIAddress *cpiInterfaceL2Group_GetSourceAddress(const CPIInterfaceL2Group *l2group);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const CPIAddress *cpiInterfaceL2Group_GetGroupAddress(const CPIInterfaceL2Group *l2group);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+IPTunnelType cpiInterfaceL2Group_GetTunnelType(const CPIInterfaceL2Group *l2group);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceStateType cpiInterfaceL2Group_GetState(const CPIInterfaceL2Group *l2group);
+#endif // libccnx_cpi_InterfaceL2Group_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceLocal.h b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceLocal.h
new file mode 100644
index 00000000..601dd554
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceLocal.h
@@ -0,0 +1,143 @@
+/*
+ * 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 cpi_InterfaceLocal.h
+ * @brief A local interface points up to the transport
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_cpi_InterfaceLocal_h
+#define libccnx_cpi_InterfaceLocal_h
+
+#include <ccnx/api/control/cpi_InterfaceType.h>
+#include <ccnx/api/control/cpi_Address.h>
+#include <ccnx/api/control/cpi_AddressList.h>
+
+struct cpi_interface_local;
+/**
+ * @see cpiInterfaceLocal_Create
+ */
+typedef struct cpi_interface_local CPIInterfaceLocal;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceLocal *cpiInterfaceLocal_Create(unsigned ifidx, CPIInterfaceStateType state, CPIAddressList *addresses);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceLocal *cpiInterfaceLocal_Copy(const CPIInterfaceLocal *local);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void cpiInterfaceLocal_Destroy(CPIInterfaceLocal **localPtr);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+unsigned cpiInterfaceLocal_GetIndex(const CPIInterfaceLocal *local);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+const CPIAddressList *cpiInterfaceLocal_GetAddresses(const CPIInterfaceLocal *local);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceStateType cpiInterfaceLocal_GetState(const CPIInterfaceLocal *local);
+#endif // libccnx_cpi_InterfaceLocal_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceSet.c b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceSet.c
new file mode 100644
index 00000000..0a9042cf
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceSet.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 <ccnx/api/control/cpi_InterfaceSet.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <LongBow/runtime.h>
+
+struct cpi_interface_set {
+ PARCArrayList *listOfInterfaces;
+};
+
+static void
+_destroyInterface(void **ifaceVoidPtr)
+{
+ cpiInterface_Destroy((CPIInterface **) ifaceVoidPtr);
+}
+
+CPIInterfaceSet *
+cpiInterfaceSet_Create(void)
+{
+ CPIInterfaceSet *set = parcMemory_AllocateAndClear(sizeof(CPIInterfaceSet));
+ assertNotNull(set, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIInterfaceSet));
+ set->listOfInterfaces = parcArrayList_Create(_destroyInterface);
+ return set;
+}
+
+void
+cpiInterfaceSet_Destroy(CPIInterfaceSet **setPtr)
+{
+ assertNotNull(setPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*setPtr, "Parameter must dereference to non-null pointer");
+
+ CPIInterfaceSet *set = *setPtr;
+ parcArrayList_Destroy(&set->listOfInterfaces);
+ parcMemory_Deallocate((void **) &set);
+ *setPtr = NULL;
+}
+
+bool
+cpiInterfaceSet_Add(CPIInterfaceSet *set, CPIInterface *iface)
+{
+ assertNotNull(set, "Parameter set must be non-null");
+ assertNotNull(iface, "Parameter iface must be non-null");
+
+ unsigned ifaceIndex = cpiInterface_GetInterfaceIndex(iface);
+ size_t length = parcArrayList_Size(set->listOfInterfaces);
+ for (size_t i = 0; i < length; i++) {
+ CPIInterface *listEntry = (CPIInterface *) parcArrayList_Get(set->listOfInterfaces, i);
+ unsigned entryInterfaceIndex = cpiInterface_GetInterfaceIndex(listEntry);
+ if (entryInterfaceIndex == ifaceIndex) {
+ return false;
+ }
+ }
+
+ parcArrayList_Add(set->listOfInterfaces, (PARCObject *) iface);
+ return true;
+}
+
+size_t
+cpiInterfaceSet_Length(const CPIInterfaceSet *set)
+{
+ assertNotNull(set, "Parameter set must be non-null");
+ return parcArrayList_Size(set->listOfInterfaces);
+}
+
+CPIInterface *
+cpiInterfaceSet_GetByOrdinalIndex(CPIInterfaceSet *set, size_t ordinalIndex)
+{
+ assertNotNull(set, "Parameter set must be non-null");
+ return (CPIInterface *) parcArrayList_Get(set->listOfInterfaces, ordinalIndex);
+}
+
+CPIInterface *
+cpiInterfaceSet_GetByInterfaceIndex(const CPIInterfaceSet *set, unsigned interfaceIndex)
+{
+ size_t length = parcArrayList_Size(set->listOfInterfaces);
+ for (size_t i = 0; i < length; i++) {
+ CPIInterface *listEntry = (CPIInterface *) parcArrayList_Get(set->listOfInterfaces, i);
+ unsigned entryInterfaceIndex = cpiInterface_GetInterfaceIndex(listEntry);
+ if (entryInterfaceIndex == interfaceIndex) {
+ return listEntry;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Uses the system name (e.g. "en0")
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIInterface *
+cpiInterfaceSet_GetByName(CPIInterfaceSet *set, const char *name)
+{
+ size_t length = parcArrayList_Size(set->listOfInterfaces);
+ for (size_t i = 0; i < length; i++) {
+ CPIInterface *listEntry = (CPIInterface *) parcArrayList_Get(set->listOfInterfaces, i);
+ if (cpiInterface_NameEquals(listEntry, name)) {
+ return listEntry;
+ }
+ }
+ return NULL;
+}
+
+bool
+cpiInterfaceSet_Equals(const CPIInterfaceSet *a, const CPIInterfaceSet *b)
+{
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ size_t length_a = parcArrayList_Size(a->listOfInterfaces);
+ size_t length_b = parcArrayList_Size(b->listOfInterfaces);
+
+ if (length_a == length_b) {
+ for (size_t i = 0; i < length_a; i++) {
+ CPIInterface *iface_a = (CPIInterface *) parcArrayList_Get(a->listOfInterfaces, i);
+
+ // the set is unique by interface id, so if it exists in set b, it
+ // exists there by interface id
+ CPIInterface *iface_b = cpiInterfaceSet_GetByInterfaceIndex(b, cpiInterface_GetInterfaceIndex(iface_a));
+ if (!cpiInterface_Equals(iface_b, iface_b)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+const char cpi_InterfaceList[] = "Interfaces";
+
+CPIInterfaceSet *
+cpiInterfaceSet_FromJson(PARCJSON *json)
+{
+ assertNotNull(json, "Parameter must be non-null");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpi_InterfaceList);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpi_InterfaceList,
+ parcJSON_ToString(json));
+ PARCJSONArray *ifaceSetJson = parcJSONValue_GetArray(value);
+
+ CPIInterfaceSet *set = cpiInterfaceSet_Create();
+
+ size_t length = parcJSONArray_GetLength(ifaceSetJson);
+ for (size_t i = 0; i < length; i++) {
+ value = parcJSONArray_GetValue(ifaceSetJson, i);
+ PARCJSON *ifaceJson = parcJSONValue_GetJSON(value);
+ CPIInterface *iface = cpiInterface_FromJson(ifaceJson);
+ cpiInterfaceSet_Add(set, iface);
+ }
+
+ return set;
+}
+
+PARCJSON *
+cpiInterfaceSet_ToJson(CPIInterfaceSet *set)
+{
+ assertNotNull(set, "Parameter must be non-null");
+
+ PARCJSONArray *interfaceList = parcJSONArray_Create();
+
+ size_t length = parcArrayList_Size(set->listOfInterfaces);
+ for (size_t i = 0; i < length; i++) {
+ CPIInterface *iface = (CPIInterface *) parcArrayList_Get(set->listOfInterfaces, i);
+ PARCJSON *json = cpiInterface_ToJson(iface);
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ parcJSON_Release(&json);
+ parcJSONArray_AddValue(interfaceList, value);
+ parcJSONValue_Release(&value);
+ }
+
+ PARCJSON *result = parcJSON_Create();
+ parcJSON_AddArray(result, cpi_InterfaceList, interfaceList);
+ parcJSONArray_Release(&interfaceList);
+
+ return result;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceSet.h b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceSet.h
new file mode 100644
index 00000000..4650c226
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceSet.h
@@ -0,0 +1,232 @@
+/*
+ * 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 cpi_InterfaceSet.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_cpi_InterfaceSet_h
+#define libccnx_cpi_InterfaceSet_h
+
+#include <ccnx/api/control/cpi_Interface.h>
+
+struct cpi_interface_set;
+/**
+ *
+ * @see cpiInterfaceSet_Create
+ */
+typedef struct cpi_interface_set CPIInterfaceSet;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceSet *cpiInterfaceSet_Create(void);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void cpiInterfaceSet_Destroy(CPIInterfaceSet **setPtr);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceSet *cpiInterfaceSet_FromJson(PARCJSON *json);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *cpiInterfaceSet_ToJson(CPIInterfaceSet *iface);
+
+/**
+ * Adds interface to set, does not allow duplicates
+ *
+ * Takes ownership of the iface memory if added
+ *
+ * Duplicates are two entries with the same interface index
+ *
+ * @param <#param1#>
+ * @return true if added, false if not (likely a duplicate)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool cpiInterfaceSet_Add(CPIInterfaceSet *set, CPIInterface *iface);
+
+/**
+ * The number of interfaces in the set
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t cpiInterfaceSet_Length(const CPIInterfaceSet *set);
+
+/**
+ * Uses the ordinal index of the interface in the Set
+ *
+ * Ranges from 0 .. <code>cpiInterfaceSet_Length()-1</code>.
+ *
+ * @param <#param1#>
+ * @return NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIInterface *cpiInterfaceSet_GetByOrdinalIndex(CPIInterfaceSet *set, size_t ordinalIndex);
+
+/**
+ * Retreives by the CPI assigned interface index
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIInterface *cpiInterfaceSet_GetByInterfaceIndex(const CPIInterfaceSet *set, unsigned interfaceIndex);
+
+/**
+ * Uses the system name (e.g. "en0")
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIInterface *cpiInterfaceSet_GetByName(CPIInterfaceSet *set, const char *name);
+
+
+/**
+ * Determine if two CPIInterfaceSet instances are equal.
+ *
+ * Two CPIInterfaceSet instances are equal if, and only if, the sets contain the same elements
+ * - order independent.
+ * Each element is compared via <code>cpiInterface_Equals()</code>
+ *
+ * The following equivalence relations on non-null `CPIInterfaceSet` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `CPIInterfaceSet_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `CPIInterfaceSet_Equals(x, y)` must return true if and only if
+ * `cpiInterfaceSet_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiInterfaceSet_Equals(x, y)` returns true and
+ * `cpiInterfaceSet_Equals(y, z)` returns true,
+ * then `cpiInterfaceSet_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `cpiInterfaceSet_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `cpiInterfaceSet_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `CPIInterfaceSet` instance.
+ * @param b A pointer to a `CPIInterfaceSet` instance.
+ * @return true if the two `CPIInterfaceSet` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIInterfaceSet *a = cpiInterfaceSet_Create();
+ * CPIInterfaceSet *b = cpiInterfaceSet_Create();
+ *
+ * if (cpiInterfaceSet_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool cpiInterfaceSet_Equals(const CPIInterfaceSet *a, const CPIInterfaceSet *b);
+#endif // libccnx_cpi_InterfaceSet_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceType.c b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceType.c
new file mode 100644
index 00000000..887d5c75
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceType.c
@@ -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.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <LongBow/runtime.h>
+
+typedef enum {
+ CPI_IFACE_LOOPBACK = 1,
+ CPI_IFACE_ETHERNET = 2,
+ CPI_IFACE_LOCALAPP = 3,
+ CPI_IFACE_TUNNEL = 4,
+ CPI_IFACE_GROUP = 5
+} CPIInterfaceType;
+
+typedef enum {
+ CPI_IFACE_UNKNOWN = 0,
+ CPI_IFACE_UP = 1,
+ CPI_IFACE_DOWN = 2
+} CPIInterfaceStateType;
+
+struct cpi_interface_types_string {
+ CPIInterfaceType type;
+ const char *str;
+} interfaceTypesArray[] = {
+ { .type = CPI_IFACE_LOOPBACK, .str = "LOOPBACK" },
+ { .type = CPI_IFACE_ETHERNET, .str = "ETHERNET" },
+ { .type = CPI_IFACE_LOCALAPP, .str = "LOCALAPP" },
+ { .type = CPI_IFACE_TUNNEL, .str = "TUNNEL" },
+ { .type = CPI_IFACE_GROUP, .str = "GROUP" },
+ { .type = 0, .str = NULL }
+};
+
+struct cpi_interface_state_types_string {
+ CPIInterfaceStateType type;
+ const char *str;
+} interfaceStateTypesArray[] = {
+ { .type = CPI_IFACE_UNKNOWN, .str = "UNKNOWN" },
+ { .type = CPI_IFACE_UP, .str = "UP" },
+ { .type = CPI_IFACE_DOWN, .str = "DOWN" },
+ { .type = 0, .str = NULL }
+};
+
+const char *
+cpiInterfaceType_ToString(CPIInterfaceType type)
+{
+ for (int i = 0; interfaceTypesArray[i].str != NULL; i++) {
+ if (interfaceTypesArray[i].type == type) {
+ return interfaceTypesArray[i].str;
+ }
+ }
+ trapIllegalValue(type, "Unknown type: %d", type);
+}
+
+CPIInterfaceType
+cpiInterfaceType_FromString(const char *str)
+{
+ for (int i = 0; interfaceTypesArray[i].str != NULL; i++) {
+ if (strcasecmp(interfaceTypesArray[i].str, str) == 0) {
+ return interfaceTypesArray[i].type;
+ }
+ }
+ // use a LongBow trap here, instead of an assertion followed by abort().
+ assertTrue(0, "Unknown stirng: %s", str);
+ abort();
+}
+
+const char *
+cpiInterfaceStateType_ToString(CPIInterfaceStateType type)
+{
+ for (int i = 0; interfaceStateTypesArray[i].str != NULL; i++) {
+ if (interfaceStateTypesArray[i].type == type) {
+ return interfaceStateTypesArray[i].str;
+ }
+ }
+ trapIllegalValue(type, "Unknown type: %d", type);
+}
+
+CPIInterfaceStateType
+cpiInterfaceStateType_FromString(const char *str)
+{
+ for (int i = 0; interfaceStateTypesArray[i].str != NULL; i++) {
+ if (strcasecmp(interfaceStateTypesArray[i].str, str) == 0) {
+ return interfaceStateTypesArray[i].type;
+ }
+ }
+ assertTrue(0, "Unknown stirng: %s", str);
+ abort();
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceType.h b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceType.h
new file mode 100644
index 00000000..17587a64
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_InterfaceType.h
@@ -0,0 +1,98 @@
+/*
+ * 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 cpi_InterfaceTypes.h
+ * @brief CPI INterface Types
+ *
+ *
+ */
+#ifndef libccnx_cpi_InterfaceTypes_h
+#define libccnx_cpi_InterfaceTypes_h
+
+typedef enum {
+ CPI_IFACE_LOOPBACK = 1,
+ CPI_IFACE_ETHERNET = 2,
+ CPI_IFACE_LOCALAPP = 3,
+ CPI_IFACE_TUNNEL = 4,
+ CPI_IFACE_GROUP = 5
+} CPIInterfaceType;
+
+typedef enum {
+ CPI_IFACE_UNKNOWN = 0,
+ CPI_IFACE_UP = 1,
+ CPI_IFACE_DOWN = 2
+} CPIInterfaceStateType;
+
+/**
+ * <#OneLineDescription#>
+ *
+ * <#Discussion#>
+ *
+ * @param [in] type An instance of `CPIInterfaceType`.
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiInterfaceType_ToString(CPIInterfaceType type);
+
+/**
+ * <#OneLineDescription#>
+ *
+ * <#Discussion#>
+ *
+ * @param str A nul-terminated C string.
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIInterfaceType cpiInterfaceType_FromString(const char *str);
+
+/**
+ * <#OneLineDescription#>
+ *
+ * <#Discussion#>
+ *
+ * @param type A CPIInterfaceStateType value.
+ * @return A nul-terminated C string.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiInterfaceStateType_ToString(CPIInterfaceStateType type);
+
+/**
+ * <#OneLineDescription#>
+ *
+ * <#Discussion#>
+ *
+ * @param str A nul-terminated C string.
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIInterfaceStateType cpiInterfaceStateType_FromString(const char *str);
+#endif // libccnx_cpi_InterfaceTypes_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Listener.c b/libccnx-transport-rta/ccnx/api/control/cpi_Listener.c
new file mode 100644
index 00000000..d8b75f9d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_Listener.c
@@ -0,0 +1,432 @@
+/*
+ * 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/api/control/cpi_Listener.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_JSON.h>
+
+#include <ccnx/api/control/controlPlaneInterface.h>
+extern uint64_t cpi_GetNextSequenceNumber(void);
+
+// JSON keys
+static const char *KEY_IFNAME = "IFNAME";
+static const char *KEY_SYMBOLIC = "SYMBOLIC";
+static const char *KEY_ETHERTYPE = "ETHERTYPE";
+
+static const char *KEY_IP_PROTOCOL = "IPROTO";
+static const char *KEY_ADDR = "ADDR";
+
+static const char *KEY_ADDLISTENER = "AddListener";
+static const char *KEY_REMOVELISTENER = "RemoveListener";
+
+typedef enum {
+ CPIListenerMode_ETHER,
+ CPIListenerMode_IP
+} _CPIListenerMode;
+
+struct cpi_listener {
+ _CPIListenerMode mode;
+ char *symbolic;
+
+ char *interfaceName;
+ uint16_t ethertype;
+
+ CPIAddress *address;
+ CPIInterfaceIPTunnelType type;
+};
+
+CPIListener *
+cpiListener_CreateEther(const char *interfaceName, uint16_t ethertype, const char *symbolic)
+{
+ assertNotNull(interfaceName, "Parameter interfaceName must be non-null");
+ assertNotNull(symbolic, "Parameter symbolic must be non-null");
+
+ CPIListener *listener = parcMemory_AllocateAndClear(sizeof(CPIListener));
+ if (listener) {
+ listener->mode = CPIListenerMode_ETHER;
+ listener->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName));
+ listener->symbolic = parcMemory_StringDuplicate(symbolic, strlen(symbolic));
+ listener->ethertype = ethertype;
+ }
+
+ return listener;
+}
+
+CPIListener *
+cpiListener_CreateIP(CPIInterfaceIPTunnelType type, CPIAddress *localAddress, const char *symbolic)
+{
+ assertNotNull(localAddress, "Parameter peerLinkAddress must be non-null");
+ assertNotNull(symbolic, "Parameter symbolic must be non-null");
+
+ CPIListener *listener = parcMemory_AllocateAndClear(sizeof(CPIListener));
+ if (listener) {
+ listener->mode = CPIListenerMode_IP;
+ listener->type = type;
+ listener->symbolic = parcMemory_StringDuplicate(symbolic, strlen(symbolic));
+ listener->address = cpiAddress_Copy(localAddress);
+ }
+
+ return listener;
+}
+
+void
+cpiListener_Release(CPIListener **listenerPtr)
+{
+ assertNotNull(listenerPtr, "Parameter listenerPtr must be non-null double pointer");
+ assertNotNull(*listenerPtr, "Parameter listenerPtr dereference to non-null pointer");
+
+ CPIListener *listener = *listenerPtr;
+
+ if (listener->symbolic) {
+ parcMemory_Deallocate((void **) &listener->symbolic);
+ }
+
+ if (listener->interfaceName) {
+ parcMemory_Deallocate((void **) &listener->interfaceName);
+ }
+
+ if (listener->address) {
+ cpiAddress_Destroy(&listener->address);
+ }
+
+ parcMemory_Deallocate((void **) &listener);
+ *listenerPtr = NULL;
+}
+
+bool
+cpiListener_Equals(const CPIListener *a, const CPIListener *b)
+{
+ if ((a == NULL && b == NULL) || a == b) {
+ // both null or identically equal
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ // only one is null
+ return false;
+ }
+
+ bool equals = false;
+ if (a->mode == b->mode) {
+ if (strcmp(a->symbolic, b->symbolic) == 0) {
+ if (a->mode == CPIListenerMode_ETHER) {
+ if (a->ethertype == b->ethertype) {
+ if (strcmp(a->interfaceName, b->interfaceName) == 0) {
+ equals = true;
+ }
+ }
+ } else {
+ if (a->type == b->type) {
+ if (cpiAddress_Equals(a->address, b->address)) {
+ equals = true;
+ }
+ }
+ }
+ }
+ }
+
+ return equals;
+}
+
+static void
+_encodeEther(const CPIListener *listener, PARCJSON *json)
+{
+ // ------ Interface Name
+ parcJSON_AddString(json, KEY_IFNAME, listener->interfaceName);
+
+ // ------ EtherType
+ parcJSON_AddInteger(json, KEY_ETHERTYPE, listener->ethertype);
+
+ // ------ Symbolic Name
+ parcJSON_AddString(json, KEY_SYMBOLIC, listener->symbolic);
+}
+
+static void
+_encodeIP(const CPIListener *listener, PARCJSON *json)
+{
+ // ------ Tunnel Type
+ const char *str = cpiInterfaceIPTunnel_TypeToString(listener->type);
+ parcJSON_AddString(json, KEY_IP_PROTOCOL, str);
+
+ // ------ Address
+ PARCJSON *addressJson = cpiAddress_ToJson(listener->address);
+ parcJSON_AddObject(json, KEY_ADDR, addressJson);
+ parcJSON_Release(&addressJson);
+
+ // ------ Symbolic Name
+ parcJSON_AddString(json, KEY_SYMBOLIC, listener->symbolic);
+}
+
+
+
+static PARCJSON *
+_cpiListener_ToJson(const CPIListener *listener)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ if (listener->mode == CPIListenerMode_ETHER) {
+ _encodeEther(listener, json);
+ } else {
+ _encodeIP(listener, json);
+ }
+
+ return json;
+}
+
+/*
+ * We want to create a JSON object that looks like this, where the operationName is either
+ * AddListener or RemoveListener.
+ *
+ * {
+ * "CPI_REQUEST" :
+ * { "SEQUENCE" : <sequence number>,
+ * <operationName> : { "IFNAME" : "em1", "SYMBOLIC" : "conn0", "PEER_ADDR" : { "ADDRESSTYPE" : "LINK", "DATA" : "AQIDBAUG" }, "ETHERTYPE" : 2049 },
+ * }
+ * }
+ */
+static CCNxControl *
+_cpiListener_CreateControlMessage(const CPIListener *listener, const char *operationName)
+{
+ PARCJSON *cpiRequest = parcJSON_Create();
+
+ // --- add the seqnum
+
+ uint64_t seqnum = cpi_GetNextSequenceNumber();
+ parcJSON_AddInteger(cpiRequest, "SEQUENCE", (int) seqnum);
+
+ // -- Add the operation
+
+ PARCJSON *operation = _cpiListener_ToJson(listener);
+ parcJSON_AddObject(cpiRequest, operationName, operation);
+ parcJSON_Release(&operation);
+
+ // -- Do the final encapusulation
+
+ PARCJSON *final = parcJSON_Create();
+ parcJSON_AddObject(final, cpiRequest_GetJsonTag(), cpiRequest);
+
+ // -- Create the CPIControlMessage
+ char *finalString = parcJSON_ToString(final);
+
+ parcJSON_Release(&cpiRequest);
+ parcJSON_Release(&final);
+
+ PARCJSON *oldJson = parcJSON_ParseString(finalString);
+ CCNxControl *result = ccnxControl_CreateCPIRequest(oldJson);
+ parcJSON_Release(&oldJson);
+
+ parcMemory_Deallocate((void **) &finalString);
+
+ return result;
+}
+
+CCNxControl *
+cpiListener_CreateAddMessage(const CPIListener *etherConn)
+{
+ assertNotNull(etherConn, "Parameter etherConn must be non-null");
+ CCNxControl *control = _cpiListener_CreateControlMessage(etherConn, KEY_ADDLISTENER);
+ return control;
+}
+
+CCNxControl *
+cpiListener_CreateRemoveMessage(const CPIListener *etherConn)
+{
+ assertNotNull(etherConn, "Parameter etherConn must be non-null");
+ CCNxControl *control = _cpiListener_CreateControlMessage(etherConn, KEY_REMOVELISTENER);
+ return control;
+}
+
+static bool
+_cpiListener_IsMessageType(const CCNxControl *control, const char *operationName)
+{
+ bool isOperation = false;
+ if (ccnxControl_IsCPI(control)) {
+ PARCJSON *oldJson = ccnxControl_GetJson(control);
+ PARCJSONValue *value = parcJSON_GetValueByName(oldJson, cpiRequest_GetJsonTag());
+ if (value != NULL) {
+ // the second array element is the key we're looking for
+ PARCJSON *innerJson = parcJSONValue_GetJSON(value);
+ PARCJSONPair *opPair = parcJSON_GetPairByIndex(innerJson, 1);
+ PARCBuffer *sBuf = parcJSONPair_GetName(opPair);
+ const char *operation = parcBuffer_Overlay(sBuf, 0);
+ if (operation && strcasecmp(operation, operationName) == 0) {
+ isOperation = true;
+ }
+ }
+ }
+
+ return isOperation;
+}
+
+bool
+cpiListener_IsAddMessage(const CCNxControl *control)
+{
+ assertNotNull(control, "Parameter control must be non-null");
+ return _cpiListener_IsMessageType(control, KEY_ADDLISTENER);
+}
+
+bool
+cpiListener_IsRemoveMessage(const CCNxControl *control)
+{
+ assertNotNull(control, "Parameter control must be non-null");
+ return _cpiListener_IsMessageType(control, KEY_REMOVELISTENER);
+}
+
+static CPIListener *
+_parseEther(PARCJSON *json)
+{
+ PARCJSONValue *value = parcJSON_GetValueByName(json, KEY_IFNAME);
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ const char *ifname = parcBuffer_Overlay(sBuf, 0);
+
+ value = parcJSON_GetValueByName(json, KEY_SYMBOLIC);
+ sBuf = parcJSONValue_GetString(value);
+ const char *symbolic = parcBuffer_Overlay(sBuf, 0);
+
+ value = parcJSON_GetValueByName(json, KEY_ETHERTYPE);
+ int ethertype = (int) parcJSONValue_GetInteger(value);
+
+ CPIListener *listener = cpiListener_CreateEther(ifname, (uint16_t) ethertype, symbolic);
+ return listener;
+}
+
+static CPIListener *
+_parseIP(PARCJSON *json)
+{
+ PARCJSONValue *value = parcJSON_GetValueByName(json, KEY_ADDR);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ KEY_ADDR,
+ parcJSON_ToString(json));
+ PARCJSON *addrJson = parcJSONValue_GetJSON(value);
+
+ CPIAddress *address = cpiAddress_CreateFromJson(addrJson);
+ assertNotNull(address, "Failed to decode the address from %s", parcJSON_ToString(addrJson));
+
+ value = parcJSON_GetValueByName(json, KEY_SYMBOLIC);
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ const char *symbolic = parcBuffer_Overlay(sBuf, 0);
+
+ value = parcJSON_GetValueByName(json, KEY_IP_PROTOCOL);
+ sBuf = parcJSONValue_GetString(value);
+ const char *typeString = parcBuffer_Overlay(sBuf, 0);
+
+ CPIInterfaceIPTunnelType type = cpiInterfaceIPTunnel_TypeFromString(typeString);
+
+ CPIListener *listener = cpiListener_CreateIP(type, address, symbolic);
+ cpiAddress_Destroy(&address);
+
+ return listener;
+}
+
+
+CPIListener *
+cpiListener_FromControl(const CCNxControl *control)
+{
+ assertNotNull(control, "Parameter control must be non-null");
+
+ CPIListener *listener = NULL;
+
+ if (ccnxControl_IsCPI(control)) {
+ PARCJSON *oldJson = ccnxControl_GetJson(control);
+ PARCJSONValue *value = parcJSON_GetValueByName(oldJson, cpiRequest_GetJsonTag());
+
+ if (value != NULL) {
+ PARCJSON *innerJson = parcJSONValue_GetJSON(value);
+ // the second array element is the key we're looking for
+ value = parcJSON_GetValueByName(innerJson, KEY_ADDLISTENER);
+ if (value == NULL) {
+ value = parcJSON_GetValueByName(innerJson, KEY_REMOVELISTENER);
+ }
+ if (value != NULL) {
+ PARCJSON *operationJson = parcJSONValue_GetJSON(value);
+
+ // if it has an interface name it's an ether
+ value = parcJSON_GetValueByName(operationJson, KEY_IFNAME);
+ if (value != NULL) {
+ listener = _parseEther(operationJson);
+ } else {
+ listener = _parseIP(operationJson);
+ }
+ }
+ }
+ }
+
+ return listener;
+}
+
+const char *
+cpiListener_GetInterfaceName(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return listener->interfaceName;
+}
+
+const char *
+cpiListener_GetSymbolicName(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return listener->symbolic;
+}
+
+CPIAddress *
+cpiListener_GetAddress(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return listener->address;
+}
+
+uint16_t
+cpiListener_GetEtherType(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return listener->ethertype;
+}
+
+bool
+cpiListener_IsEtherEncap(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return listener->mode == CPIListenerMode_ETHER;
+}
+
+
+bool
+cpiListener_IsIPEncap(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return listener->mode == CPIListenerMode_IP;
+}
+
+bool
+cpiListener_IsProtocolUdp(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return (listener->mode == CPIListenerMode_IP && listener->type == IPTUN_UDP);
+}
+
+bool
+cpiListener_IsProtocolTcp(const CPIListener *listener)
+{
+ assertNotNull(listener, "Parameter listener must be non-null");
+ return (listener->mode == CPIListenerMode_IP && listener->type == IPTUN_TCP);
+}
+
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Listener.h b/libccnx-transport-rta/ccnx/api/control/cpi_Listener.h
new file mode 100644
index 00000000..13cf42ce
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_Listener.h
@@ -0,0 +1,427 @@
+/*
+ * 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 cpi_Listener.h
+ * @brief Represents a protocol listener
+ *
+ * A protocol listener is the tuple (protocol, local address), where protocol is one
+ * of TCP, UDP, Ether, etc., local address is a CPI address. For IP protocols,
+ * local address is an (ip address, port) pair. For Ethernet, it is a (mac address, ethertype) pair.
+ *
+ */
+
+#ifndef CCNx_Control_API_cpi_Listener_h
+#define CCNx_Control_API_cpi_Listener_h
+
+struct cpi_listener;
+typedef struct cpi_listener CPIListener;
+
+#include <ccnx/api/control/cpi_Address.h>
+#include <ccnx/api/control/cpi_ControlMessage.h>
+
+/**
+ * Creates a CPIListener object
+ *
+ * The symbolic name represents this listener and may be used by other commands. It must be
+ * unique, otherwise the command will fail when sent to the forwarder.
+ *
+ * @param [in] interfaceName The name of the local interface
+ * @param [in] ethertype The ethertype to use (host byte order)
+ * @param [in] symbolic The user-defined symbolic name
+ *
+ * @return non-null An Allocated object
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ * cpiListener_Release(&listener);
+ * }
+ * @endcode
+ */
+CPIListener *cpiListener_CreateEther(const char *interfaceName, uint16_t ethertype, const char *symbolic);
+
+/**
+ * Creates a CPIListener object
+ *
+ * The symbolic name represents this connection and may be used by other commands. It must be
+ * unique, otherwise the command will fail when sent to the forwarder. IPv4 and IPv6 are differentiated
+ * based on the address.
+ *
+ * @param [in] type The local address encapsulation type
+ * @param [in] localAddress The local address to bind to
+ * @param [in] symbolic The user-defined symbolic name
+ *
+ * @return non-null An Allocated object
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr_in sin;
+ * memset(&sin, 0, sizeof(sin));
+ * sin.sin_family = AF_INET;
+ * sin.sin_port = htons(port);
+ * inet_aton(addressString, &sin.sin_addr);
+ * CPIAddress *address = cpiAddress_CreateFromInet(&sin);
+ * CPIListener *listener = cpiListener_CreateIP(IPTUN_UDP, address, "fido");
+ *
+ * cpiAddress_Destroy(&address);
+ * cpiListener_Release(&listener);
+ * }
+ * @endcode
+ */
+CPIListener *cpiListener_CreateIP(CPIInterfaceIPTunnelType type, CPIAddress *localAddress, const char *symbolic);
+
+/**
+ * Releases a reference count to the object
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in,out] etherConnPtr A pointer to an etherConn object, will be null'd.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ * cpiListener_Release(&listener);
+ * }
+ * @endcode
+ */
+void cpiListener_Release(CPIListener **etherConnPtr);
+
+/**
+ * Determine if two CPIListener instances are equal.
+ *
+ * Two CPIListener instances are equal if, and only if,
+ * they are either both null or both non-null and compare
+ * as equal field-for-field.
+ *
+ * The interface name is case sensitive, so "ETH0" is not the same as "eth0".
+ *
+ *
+ * The following equivalence relations on non-null `CPIListener` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `CPIListener_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `cpiListener_Equals(x, y)` must return true if and only if
+ * `cpiListener_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiListener_Equals(x, y)` returns true and
+ * `cpiListener_Equals(y, z)` returns true,
+ * then `cpiListener_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `cpiListener_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `cpiListener_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `CPIListener` instance.
+ * @param b A pointer to a `CPIListener` instance.
+ * @return true if the two `CPIListener` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIListener *a = cpiListener_Create();
+ * CPIListener *b = cpiListener_Create();
+ *
+ * if (cpiListener_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+
+bool cpiListener_Equals(const CPIListener *a, const CPIListener *b);
+
+/**
+ * Creates a control message to add the listener
+ *
+ * An add message indicates to the forwarder that it should add the listener.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null a CPI control message
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ * CCNxControl *control = cpiListener_CreateAddMessage(listener);
+ * cpiListener_Release(&listener);
+ *
+ * ccnxPortal_Send(portal, control, CCNxStackTimeout_Never);
+ * ccnxControl_Release(&control);
+ * }
+ * @endcode
+ */
+CCNxControl *cpiListener_CreateAddMessage(const CPIListener *etherConn);
+
+/**
+ * Creates a control message to remove the connection
+ *
+ * A remove message indicates to the forwarder that it should remove the listener.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return non-null a CPI control message
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ * CCNxControl *control = cpiListener_CreateRemoveMessage(listener);
+ * cpiListener_Release(&listener);
+ *
+ * ccnxPortal_Send(portal, control, CCNxStackTimeout_Never);
+ * ccnxControl_Release(&control);
+ * }
+ * @endcode
+ */
+CCNxControl *cpiListener_CreateRemoveMessage(const CPIListener *etherConn);
+
+/**
+ * Checks if the control message is an Add command
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] control An allocated CCNxControl message
+ *
+ * @return true Message is an Add command for a Listener
+ * @return false Message is not an Add command for a Listener
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *msg = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ * if (ccnxMetaMessage_IsControl(msg)) {
+ * CCNxControl *control = ccnxMetaMessage_GetControl(msg);
+ * if (cpiListener_IsAddMessage(control)) {
+ * // process an add listener request
+ * }
+ * }
+ * ccnxMetaMessage_Release(&msg);
+ * }
+ * @endcode
+ */
+bool cpiListener_IsAddMessage(const CCNxControl *control);
+
+/**
+ * Checks if the message is a Remove command
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] control A CCNx Control message
+ *
+ * @return true Message is an Remove command for a Listener
+ * @return false Message is not Remove Add command for a Listener
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *msg = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ * if (ccnxMetaMessage_IsControl(msg)) {
+ * CCNxControl *control = ccnxMetaMessage_GetControl(msg);
+ * if (cpiListener_IsRemoveMessage(control)) {
+ * // process a remove listener request
+ * }
+ * }
+ * ccnxMetaMessage_Release(&msg);
+ * }
+ * @endcode
+ */
+bool cpiListener_IsRemoveMessage(const CCNxControl *control);
+
+/**
+ * Creates an object from the control message
+ *
+ * The object does not carry any sense of Add or Remove, that is only part of the
+ * Control message. You must release the object when done.
+ *
+ * @param [in] control A CCNx Control message
+ *
+ * @return non-null An Allocated object
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *msg = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ * if (ccnxMetaMessage_IsControl(msg)) {
+ * CCNxControl *control = ccnxMetaMessage_GetControl(msg);
+ * if (cpiListener_IsRemoveMessage(control)) {
+ * // process a remove listener request
+ * CPIListener *listener = cpiListener_FromControl(control);
+ * ...
+ * cpiListener_Release(&listener);
+ * }
+ * }
+ * ccnxMetaMessage_Release(&msg);
+ * }
+ * @endcode
+ */
+CPIListener *cpiListener_FromControl(const CCNxControl *control);
+
+/**
+ * Determines if the encapsulation is an Ethernet protocol
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] listener An allocated CPIListener
+ *
+ * @retval true It's Ethernet based
+ * @retval false It's not
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool cpiListener_IsEtherEncap(const CPIListener *listener);
+
+/**
+ * Determines if the encapsulation is an IP-based protocol
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] listener An allocated CPIListener
+ *
+ * @retval true It's IP based
+ * @retval false It's not
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool cpiListener_IsIPEncap(const CPIListener *listener);
+
+/**
+ * Returns the Ethertype for an Ethernet encapsulation
+ *
+ * The returned value is in host byte order
+ *
+ * @param [in] listener An allocated CPIListener
+ *
+ * @retval 0 Not Ethernet encapsulation
+ * @retval positive The ethertype
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint16_t cpiListener_GetEtherType(const CPIListener *listener);
+
+/**
+ * Returns the interface name
+ *
+ * The caller should duplicate the string if it will be stored.
+ *
+ * @param [in] etherConn An allocated CPIListener
+ *
+ * @return non-null The interface name.
+ * @return null An error (or not Ethernet encapsulation)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiListener_GetInterfaceName(const CPIListener *etherConn);
+
+/**
+ * Returns the symbolic name
+ *
+ * The caller should duplicate the string if it will be stored.
+ *
+ * @param [in] listener An allocated CPIListener
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiListener_GetSymbolicName(const CPIListener *listener);
+
+/**
+ * Returns the address (LINK mac address, or INET or INET6 ip address)
+ *
+ * Returns the local address to use for the listener. The address type is
+ * as appropriate for the encapsulation.
+ *
+ * @param [in] listener An allocated CPIListener
+ *
+ * @return non-null The peer's link address
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIAddress *cpiListener_GetAddress(const CPIListener *listener);
+
+/**
+ * For IP encapsulation, tests if the IP protocol is UDP
+ *
+ * Tests if the IP protocol is UDP. If the protocol is not UDP or the encapsulation
+ * is not IP, returns false.
+ *
+ * @param [in] listener An allocated CPIListener
+ *
+ * @retval true IP protocol is UDP
+ * @retval false Not IP or not IP and UDP
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool cpiListener_IsProtocolUdp(const CPIListener *listener);
+
+/**
+ * For IP encapsulation, tests if the IP protocol is TCP
+ *
+ * Tests if the IP protocol is TCP. If the protocol is not TCP or the encapsulation
+ * is not IP, returns false.
+ *
+ * @param [in] listener An allocated CPIListener
+ *
+ * @retval true IP protocol is TCP
+ * @retval false Not IP or not IP and TCP
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool cpiListener_IsProtocolTcp(const CPIListener *listener);
+
+#endif // CCNx_Control_API_cpi_Listener_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ManageCaches.c b/libccnx-transport-rta/ccnx/api/control/cpi_ManageCaches.c
new file mode 100644
index 00000000..43cc2ae8
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ManageCaches.c
@@ -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.
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include <ccnx/api/control/controlPlaneInterface.h>
+#include <ccnx/api/control/cpi_ManageCaches.h>
+#include <LongBow/runtime.h>
+
+#include "cpi_private.h"
+
+static const char *cpiCacheStoreOn = "CACHE_STORE_ON";
+static const char *cpiCacheStoreOff = "CACHE_STORE_OFF";
+static const char *cpiCacheServeOn = "CACHE_SERVE_ON";
+static const char *cpiCacheServeOff = "CACHE_SERVE_OFF";
+static const char *cpiCacheClear = "CACHE_CLEAR";
+
+PARCJSON *
+cpiManageChaces_CreateCacheClearRequest()
+{
+ PARCJSON *json = parcJSON_Create();
+ PARCJSON *result = cpi_CreateRequest(cpiCacheClear, json);
+ parcJSON_Release(&json);
+
+ return result;
+}
+
+
+PARCJSON *
+cpiManageChaces_CreateCacheStoreRequest(bool activate)
+{
+ PARCJSON *json = parcJSON_Create();
+ PARCJSON *result;
+ if (activate) {
+ result = cpi_CreateRequest(cpiCacheStoreOn, json);
+ } else {
+ result = cpi_CreateRequest(cpiCacheStoreOff, json);
+ }
+ parcJSON_Release(&json);
+
+ return result;
+}
+
+
+PARCJSON *
+cpiManageChaces_CreateCacheServeRequest(bool activate)
+{
+ PARCJSON *json = parcJSON_Create();
+ PARCJSON *result;
+ if (activate) {
+ result = cpi_CreateRequest(cpiCacheServeOn, json);
+ } else {
+ result = cpi_CreateRequest(cpiCacheServeOff, json);
+ }
+ parcJSON_Release(&json);
+
+ return result;
+}
+
+
+const char *
+cpiManageChaces_CacheStoreOnJsonTag()
+{
+ return cpiCacheStoreOn;
+}
+
+const char *
+cpiManageChaces_CacheStoreOffJsonTag()
+{
+ return cpiCacheStoreOff;
+}
+
+const char *
+cpiManageChaces_CacheServeOnJsonTag()
+{
+ return cpiCacheServeOn;
+}
+
+const char *
+cpiManageChaces_CacheServeOffJsonTag()
+{
+ return cpiCacheServeOff;
+}
+
+const char *
+cpiManageChaces_CacheClearJsonTag()
+{
+ return cpiCacheClear;
+}
+
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ManageCaches.h b/libccnx-transport-rta/ccnx/api/control/cpi_ManageCaches.h
new file mode 100644
index 00000000..31c039df
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ManageCaches.h
@@ -0,0 +1,35 @@
+/*
+ * 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_cpi_ManageCaches_h
+#define libccnx_cpi_ManageCaches_h
+
+
+PARCJSON *cpiManageChaces_CreateCacheStoreRequest(bool activate);
+PARCJSON *cpiManageChaces_CreateCacheServeRequest(bool activate);
+PARCJSON *cpiManageChaces_CreateCacheClearRequest();
+
+//const char *cpiLinks_AddEtherConnectionJasonTag();
+
+const char *cpiManageChaces_CacheStoreOnJsonTag();
+
+const char *cpiManageChaces_CacheStoreOffJsonTag();
+
+const char *cpiManageChaces_CacheServeOnJsonTag();
+
+const char *cpiManageChaces_CacheServeOffJsonTag();
+
+const char *cpiManageChaces_CacheClearJsonTag();
+#endif
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ManageLinks.c b/libccnx-transport-rta/ccnx/api/control/cpi_ManageLinks.c
new file mode 100644
index 00000000..4e198033
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ManageLinks.c
@@ -0,0 +1,188 @@
+/*
+ * 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/api/control/controlPlaneInterface.h>
+#include <ccnx/api/control/cpi_InterfaceIPTunnelList.h>
+#include <ccnx/api/control/cpi_ManageLinks.h>
+#include <LongBow/runtime.h>
+
+#include "cpi_private.h"
+
+static const char *cpiInterfaceList = "INTERFACE_LIST";
+static const char *cpiCreateTunnel = "CREATE_TUNNEL";
+static const char *cpiRemoveTunnel = "REMOVE_TUNNEL";
+static const char *cpiConnectionList = "CONNECTION_LIST";
+static const char *cpiSetWldr = "SET_WLDR";
+
+PARCJSON *
+cpiLinks_CreateInterfaceListRequest(void)
+{
+ PARCJSON *json = parcJSON_Create();
+ PARCJSON *result = cpi_CreateRequest(cpiInterfaceList, json);
+ parcJSON_Release(&json);
+
+ return result;
+}
+
+bool cpiLinks_IsInterfaceListResponse(CCNxControl *control);
+
+CPIInterfaceSet *
+cpiLinks_InterfacesFromControlMessage(CCNxControl *response)
+{
+ PARCJSON *json = ccnxControl_GetJson(response);
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpiResponse_GetJsonTag());
+ PARCJSON *inner_json = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(inner_json, cpiLinks_InterfaceListJsonTag());
+ PARCJSON *operation = parcJSONValue_GetJSON(value);
+
+ return cpiInterfaceSet_FromJson(operation);
+}
+
+CPIInterfaceIPTunnel *
+cpiLinks_CreateIPTunnelFromControlMessage(CCNxControl *response)
+{
+ PARCJSON *json = ccnxControl_GetJson(response);
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpiRequest_GetJsonTag());
+ if (value == NULL) {
+ value = parcJSON_GetValueByName(json, cpiResponse_GetJsonTag());
+ }
+ PARCJSON *inner_json = parcJSONValue_GetJSON(value);
+ value = parcJSON_GetValueByName(inner_json, cpiLinks_CreateTunnelJsonTag());
+ if (value == NULL) {
+ value = parcJSON_GetValueByName(inner_json, cpiLinks_RemoveTunnelJsonTag());
+ }
+ PARCJSON *operation = parcJSONValue_GetJSON(value);
+ return cpiInterfaceIPTunnel_CreateFromJson(operation);
+}
+
+PARCJSON *
+cpiLinks_CreateConnectionListRequest()
+{
+ PARCJSON *json = parcJSON_Create();
+ PARCJSON *result = cpi_CreateRequest(cpiConnectionList, json);
+ parcJSON_Release(&json);
+
+ return result;
+}
+
+
+CPIConnectionList *
+cpiLinks_ConnectionListFromControlMessage(CCNxControl *response)
+{
+ PARCJSON *json = ccnxControl_GetJson(response);
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpiRequest_GetJsonTag());
+ if (value == NULL) {
+ value = parcJSON_GetValueByName(json, cpiResponse_GetJsonTag());
+ }
+ PARCJSON *inner_json = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(inner_json, cpiLinks_ConnectionListJsonTag());
+ PARCJSON *operation = parcJSONValue_GetJSON(value);
+ return cpiConnectionList_FromJson(operation);
+}
+
+PARCJSON *
+cpiLinks_CreateIPTunnel(const CPIInterfaceIPTunnel *iptun)
+{
+ PARCJSON *tunnelJson = cpiInterfaceIPTunnel_ToJson(iptun);
+ PARCJSON *result = cpi_CreateRequest(cpiCreateTunnel, tunnelJson);
+ parcJSON_Release(&tunnelJson);
+
+ return result;
+}
+
+PARCJSON *
+cpiLinks_RemoveIPTunnel(const CPIInterfaceIPTunnel *iptun)
+{
+ PARCJSON *tunnelJson = cpiInterfaceIPTunnel_ToJson(iptun);
+ PARCJSON *result = cpi_CreateRequest(cpiRemoveTunnel, tunnelJson);
+ parcJSON_Release(&tunnelJson);
+
+ return result;
+}
+
+CCNxControl *
+cpiLinks_SetInterfaceState(unsigned ifidx, CPIInterfaceStateType state)
+{
+ return NULL;
+}
+
+CCNxControl *
+cpiLinks_RemoveInterface(unsigned ifidx)
+{
+ return NULL;
+}
+
+const char *
+cpiLinks_InterfaceListJsonTag()
+{
+ return cpiInterfaceList;
+}
+
+const char *
+cpiLinks_CreateTunnelJsonTag()
+{
+ return cpiCreateTunnel;
+}
+
+const char *
+cpiLinks_RemoveTunnelJsonTag()
+{
+ return cpiRemoveTunnel;
+}
+
+const char *
+cpiLinks_ConnectionListJsonTag()
+{
+ return cpiConnectionList;
+}
+
+PARCJSON *
+cpiLinks_CreateSetWldrRequest(const CPIManageWldr *cpiWldr)
+{
+ PARCJSON *json = cpiManageWldr_ToJson(cpiWldr);
+ PARCJSON *result = cpi_CreateRequest(cpiSetWldr, json);
+ parcJSON_Release(&json);
+
+ return result;
+}
+
+CPIManageWldr *
+cpiLinks_ManageWldrFromControlMessage(CCNxControl *control)
+{
+ assertNotNull(control, "Parameter control must be non-null");
+ PARCJSON *json = ccnxControl_GetJson(control);
+
+ PARCJSONPair *cpiWldrOpPair = cpi_ParseRequest(json);
+
+ PARCJSON *cpiWldrJson = parcJSONValue_GetJSON(parcJSONPair_GetValue(cpiWldrOpPair));
+ CPIManageWldr *cpiWldr = cpiManageWldr_FromJson(cpiWldrJson);
+
+ return cpiWldr;
+
+
+ return cpiWldr;
+}
+
+const char *
+cpiLinks_SetWldrJsonTag()
+{
+ return cpiSetWldr;
+}
+
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ManageLinks.h b/libccnx-transport-rta/ccnx/api/control/cpi_ManageLinks.h
new file mode 100644
index 00000000..7abd5dcd
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ManageLinks.h
@@ -0,0 +1,248 @@
+/*
+ * 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 cpi_ManageLinks.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_cpi_ManageLinks_h
+#define libccnx_cpi_ManageLinks_h
+
+#include <ccnx/api/control/cpi_ConnectionList.h>
+#include <ccnx/api/control/cpi_ControlMessage.h>
+#include <ccnx/api/control/cpi_ManageWldr.h>
+#include <ccnx/api/control/cpi_InterfaceType.h>
+#include <ccnx/api/control/cpi_InterfaceIPTunnel.h>
+#include <ccnx/api/control/cpi_InterfaceIPTunnelList.h>
+#include <ccnx/api/control/cpi_InterfaceSet.h>
+
+
+/**
+ * Create a control message that asks the forwarder to return a list of connections
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *cpiLinks_CreateConnectionListRequest();
+
+/**
+ * Returns a native object from a control message of connections
+ *
+ * The decoder of the response to <code>cpiLinks_CreateConnectionListRequest()</code>
+ *
+ * @param <#param1#>
+ * @return An allocated object, you must destroy it.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIConnectionList *cpiLinks_ConnectionListFromControlMessage(CCNxControl *response);
+
+/**
+ * Generate a request for a list of all interfaces
+ *
+ * The transport should resond with a CPI Response message.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *cpiLinks_CreateInterfaceListRequest(void);
+
+/**
+ * Parse a control message into a list of interfaces
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIInterfaceSet *cpiLinks_InterfacesFromControlMessage(CCNxControl *response);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *cpiLinks_CreateIPTunnel(const CPIInterfaceIPTunnel *iptun);
+
+PARCJSON *cpiLinks_RemoveIPTunnel(const CPIInterfaceIPTunnel *iptun);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIInterfaceIPTunnel *cpiLinks_CreateIPTunnelFromControlMessage(CCNxControl *response);
+
+/**
+ * Set an interface to UP or DOWN
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxControl *cpiLinks_SetInterfaceState(unsigned ifidx, CPIInterfaceStateType state);
+
+/**
+ * Removes an interface
+ *
+ * If it is a virtual interface created through the ControlPlaneInterface, it
+ * is complete removed.
+ *
+ * Trying to remove a physical interface will result in it going down, but it
+ * might not be removed from the system.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxControl *cpiLinks_RemoveInterface(unsigned ifidx);
+
+/**
+ * The key name for an InterfaceList branch
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return Do not free it.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiLinks_InterfaceListJsonTag();
+
+/**
+ * The string tag used in JSON for a Create Tunnel request
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return Do not free it
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiLinks_CreateTunnelJsonTag();
+
+/**
+ * The string tag used in JSON for a Remove Tunnel request
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return Do not free it
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiLinks_RemoveTunnelJsonTag();
+
+/**
+ * The string tag used in JSON for a Connection List request
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return Do not free it
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiLinks_ConnectionListJsonTag();
+
+/**
+ * The string tag used in JSON to add an Ethernet connection
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return Do not free it
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *cpiLinks_AddEtherConnectionJasonTag();
+
+PARCJSON *cpiLinks_CreateSetWldrRequest(const CPIManageWldr *cpiWldr);
+
+CPIManageWldr *cpiLinks_ManageWldrFromControlMessage(CCNxControl *control);
+
+const char *cpiLinks_SetWldrJsonTag();
+
+#endif // libccnx_cpi_ManageLinks_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ManageWldr.c b/libccnx-transport-rta/ccnx/api/control/cpi_ManageWldr.c
new file mode 100644
index 00000000..d0799d6b
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ManageWldr.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 <stdlib.h>
+#include <sys/time.h>
+
+#include <ccnx/api/control/cpi_ManageWldr.h>
+#include <ccnx/api/control/controlPlaneInterface.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <LongBow/runtime.h>
+
+#include "cpi_private.h"
+
+static const char *cpiWldrString = "WLDR";
+static const char *cpiWldrConn = "CONN";
+static const char *cpiWldrOn = "ON";
+static const char *cpiWldrOff = "OFF";
+
+struct cpi_manage_wldr {
+ char *connectionId;
+ bool active;
+};
+
+void
+cpiManageWldr_Destroy(CPIManageWldr **cpiWldrPtr)
+{
+ assertNotNull(cpiWldrPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*cpiWldrPtr, "Parameter must dereference to non-null pointer");
+ CPIManageWldr *cpiWldr = *cpiWldrPtr;
+
+ parcMemory_Deallocate((void **) &cpiWldr->connectionId);
+ parcMemory_Deallocate((void **) &cpiWldr);
+
+ *cpiWldrPtr = NULL;
+}
+
+CPIManageWldr *
+cpiManageWldr_Create(bool active, char *conn)
+{
+ CPIManageWldr *cpiWldr = parcMemory_AllocateAndClear(sizeof(cpiWldr));
+ assertNotNull(cpiWldr, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(cpiWldr));
+
+ cpiWldr->connectionId = parcMemory_StringDuplicate(conn, strlen(conn));
+ cpiWldr->active = active;
+
+ return cpiWldr;
+}
+
+char *
+CPIManageWldr_ToString(CPIManageWldr *cpiWldr)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcBufferComposer_PutString(composer, cpiManageWldr_GetConnection(cpiWldr));
+
+ parcBufferComposer_PutString(composer, cpiWldrString);
+
+ if (cpiManageWldr_IsActive(cpiWldr)) {
+ parcBufferComposer_PutString(composer, cpiWldrOn);
+ } else {
+ parcBufferComposer_PutString(composer, cpiWldrOff);
+ }
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ return result;
+}
+
+CPIManageWldr *
+cpiManageWldr_Copy(const CPIManageWldr *original)
+{
+ assertNotNull(original, "Parameter a must be non-null");
+ CPIManageWldr *copy = cpiManageWldr_Create(original->active,
+ parcMemory_StringDuplicate(original->connectionId, strlen(original->connectionId)));
+
+ return copy;
+}
+
+bool
+cpiManageWldr_Equals(const CPIManageWldr *a, const CPIManageWldr *b)
+{
+ assertNotNull(a, "Parameter a must be non-null");
+ assertNotNull(b, "Parameter b must be non-null");
+ if (a == b) {
+ return true;
+ }
+
+ if ((a->active == b->active) && (strcmp(a->connectionId, b->connectionId) == 0)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool
+cpiManageWldr_IsActive(const CPIManageWldr *cpiWldr)
+{
+ assertNotNull(cpiWldr, "Parameter must be non-null");
+ return cpiWldr->active;
+}
+
+const char *
+cpiManageWldr_GetConnection(const CPIManageWldr *cpiWldr)
+{
+ assertNotNull(cpiWldr, "Parameter must be non-null");
+ return cpiWldr->connectionId;
+}
+
+
+PARCJSON *
+cpiManageWldr_ToJson(const CPIManageWldr *cpiWldr)
+{
+ PARCJSON *wldrJson = parcJSON_Create();
+
+ parcJSON_AddString(wldrJson, cpiWldrConn, cpiWldr->connectionId);
+
+ if (cpiWldr->active) {
+ parcJSON_AddString(wldrJson, cpiWldrString, cpiWldrOn);
+ } else {
+ parcJSON_AddString(wldrJson, cpiWldrString, cpiWldrOff);
+ }
+
+ return wldrJson;
+}
+CPIManageWldr *
+cpiManageWldr_FromJson(PARCJSON *json)
+{
+ assertNotNull(json, "Parameter json must be non-null");
+ PARCJSON *cpiWldrJson = json;
+
+ PARCJSONValue *value = parcJSON_GetValueByName(cpiWldrJson, cpiWldrConn);
+ assertNotNull(value, "Couldn't locate tag %s in: %s", cpiWldrConn, parcJSON_ToString(json));
+
+ PARCBuffer *wBuf = parcJSONValue_GetString(value);
+ char *conn = parcBuffer_Overlay(wBuf, 0);
+
+ value = parcJSON_GetValueByName(cpiWldrJson, cpiWldrString);
+ assertNotNull(value, "Couldn't locate tag %s in: %s", cpiWldrString, parcJSON_ToString(json));
+
+ wBuf = parcJSONValue_GetString(value);
+ char *active = parcBuffer_Overlay(wBuf, 0);
+
+ CPIManageWldr *cpiWldr;
+ if (strcmp(active, cpiWldrOn) == 0) {
+ cpiWldr = cpiManageWldr_Create(true, conn);
+ } else {
+ cpiWldr = cpiManageWldr_Create(false, conn);
+ }
+
+ return cpiWldr;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_ManageWldr.h b/libccnx-transport-rta/ccnx/api/control/cpi_ManageWldr.h
new file mode 100644
index 00000000..eae06e5f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_ManageWldr.h
@@ -0,0 +1,49 @@
+/*
+ * 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_cpi_ManageWldr_h
+#define libccnx_cpi_ManageWldr_h
+
+#include <parc/algol/parc_JSON.h>
+
+struct cpi_manage_wldr;
+/**
+ * @typedef CPIManageWldr
+ */
+typedef struct cpi_manage_wldr CPIManageWldr;
+
+/**
+ */
+
+void cpiManageWldr_Destroy(CPIManageWldr **cpiWldrPtr);
+
+CPIManageWldr *cpiManageWldr_Create(bool active, char *conn);
+
+char *CPIManageWldr_ToString(CPIManageWldr *cpiWldr);
+
+CPIManageWldr *cpiManageWldr_Copy(const CPIManageWldr *original);
+
+bool cpiManageWldr_Equals(const CPIManageWldr *a, const CPIManageWldr *b);
+
+bool cpiManageWldr_IsActive(const CPIManageWldr *cpiWldr);
+
+const char *cpiManageWldr_GetConnection(const CPIManageWldr *cpiWldr);
+
+PARCJSON *cpiManageWldr_ToJson(const CPIManageWldr *cpiWldr);
+
+
+CPIManageWldr *cpiManageWldr_FromJson(PARCJSON *json);
+
+#endif // libccnx_cpi_ManageWldr_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_NameRouteProtocolType.c b/libccnx-transport-rta/ccnx/api/control/cpi_NameRouteProtocolType.c
new file mode 100644
index 00000000..ebde3d19
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_NameRouteProtocolType.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 <pthread.h>
+#include <string.h>
+#include <strings.h>
+#include <netinet/in.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/api/control/cpi_NameRouteProtocolType.h>
+
+struct name_route_protocol_type_s {
+ const char *str;
+ CPINameRouteProtocolType type;
+} nameRouteProtocolTypeString[] = {
+ { .str = "LOCAL", .type = cpiNameRouteProtocolType_LOCAL },
+ { .str = "CONNECTED", .type = cpiNameRouteProtocolType_CONNECTED },
+ { .str = "STATIC", .type = cpiNameRouteProtocolType_STATIC },
+ { .str = "ACORN", .type = cpiNameRouteProtocolType_ACORN },
+ { .str = NULL, .type = 0 }
+};
+
+const char *
+cpiNameRouteProtocolType_ToString(CPINameRouteProtocolType type)
+{
+ for (int i = 0; nameRouteProtocolTypeString[i].str != NULL; i++) {
+ if (nameRouteProtocolTypeString[i].type == type) {
+ return nameRouteProtocolTypeString[i].str;
+ }
+ }
+ trapIllegalValue(type, "Unknown type: %d", type);
+}
+
+CPINameRouteProtocolType
+cpiNameRouteProtocolType_FromString(const char *str)
+{
+ for (int i = 0; nameRouteProtocolTypeString[i].str != NULL; i++) {
+ if (strcasecmp(nameRouteProtocolTypeString[i].str, str) == 0) {
+ return nameRouteProtocolTypeString[i].type;
+ }
+ }
+ trapIllegalValue(type, "Unknown type name: %s", str);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_NameRouteProtocolType.h b/libccnx-transport-rta/ccnx/api/control/cpi_NameRouteProtocolType.h
new file mode 100644
index 00000000..29d75ad4
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_NameRouteProtocolType.h
@@ -0,0 +1,95 @@
+/*
+ * 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 cpi_NameRouteProtocolType.h
+ * @brief Specifies the reason for or creator of a route (i.e. the protocol that created the route)
+ *
+ * A LOCAL route points to an application running on the localhost.
+ *
+ * A CONNECTED route exists because the described destination is directly connected to the localhost. For
+ * example, a route to a link local network name would be CONNECTED.
+ *
+ * A STATIC route is administratively created, such as via the "metis_control" program or via the
+ * configuration file.
+ *
+ * An ACORN route is dynamically created by the ACRON routing protocol.
+ *
+ */
+#ifndef libccnx_cpi_NameRouteProtocolType_h
+#define libccnx_cpi_NameRouteProtocolType_h
+
+
+
+/**
+ * @typedef CPINameRouteProtocolType
+ * @abstract Enumerates the protocol that created a route
+ * @constant cpiNameRouteProtocolType_LOCAL An application running on the localhost
+ * @constant cpiNameRouteProtocolType_CONNECTED A directly connected destination
+ * @constant cpiNameRouteProtocolType_STATIC Administratively created
+ * @constant cpiNameRouteProtocolType_ACORN The ACORN routing protocol
+ */
+typedef enum {
+ cpiNameRouteProtocolType_LOCAL = 0, // local face to app
+ cpiNameRouteProtocolType_CONNECTED = 1, // directly connected network
+ cpiNameRouteProtocolType_STATIC = 2, // administrative static route
+ cpiNameRouteProtocolType_ACORN = 20
+} CPINameRouteProtocolType;
+
+/**
+ * Return the string representation of the specified `CPINameRouteProtocolType`.
+ *
+ * The returned string does not need to be freed.
+ *
+ * @param [in] type The type to represent as a string.
+ *
+ * @return The string representation of the specified 'CPINameRouteProtocolType'.
+ *
+ * Example:
+ * @code
+ * {
+ * CPINameRouteProtocolType type = ROUTE_PROTO_CONNECTED;
+ *
+ * char *name = cpiNameRouteProtocolType_ToString(type);
+ *
+ * printf("NameRouteProtocolType is %s\n", name);
+ * }
+ * @endcode
+ *
+ * @see cpiNameRouteProtocolType_FromString
+ */
+const char *cpiNameRouteProtocolType_ToString(CPINameRouteProtocolType type);
+
+/**
+ * Given a string describing a `CPINameRouteProtocolType`, return the matching `CPINameRouteProtocolType`.
+ *
+ * If an invalid string is specified, the program will terminate with an IllegalValue exception.
+ * Possible values are: "LOCAL", "CONNECTED", "STATIC", and "ACORN".
+ *
+ * @param [in] str A pointer to a string representation of the desired `CPINameRouteProtocolType`.
+ *
+ * @return The `CPINameRouteProtocolType` matching the specified string.
+ *
+ * Example:
+ * @code
+ * {
+ * CPINameRouteProtocolType type = cpiNameRouteProtocolType_FromString("STATIC");
+ * }
+ * @endcode
+ *
+ * @see cpiNameRouteProtocolType_ToString
+ */
+CPINameRouteProtocolType cpiNameRouteProtocolType_FromString(const char *str);
+#endif // libccnx_cpi_NameRouteProtocolType_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_NameRouteType.c b/libccnx-transport-rta/ccnx/api/control/cpi_NameRouteType.c
new file mode 100644
index 00000000..44a5d943
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_NameRouteType.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 <pthread.h>
+#include <string.h>
+#include <strings.h>
+#include <netinet/in.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/api/control/cpi_NameRouteType.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Base64.h>
+
+#include "controlPlaneInterface.h"
+#include "cpi_private.h"
+
+struct name_route_type_s {
+ const char *str;
+ CPINameRouteType type;
+} nameRouteTypeString[] = {
+ { .str = "EXACT", .type = cpiNameRouteType_EXACT_MATCH },
+ { .str = "LONGEST", .type = cpiNameRouteType_LONGEST_MATCH },
+ { .str = "DEFAULT", .type = cpiNameRouteType_DEFAULT },
+ { .str = NULL, .type = 0 }
+};
+
+const char *
+cpiNameRouteType_ToString(CPINameRouteType type)
+{
+ for (int i = 0; nameRouteTypeString[i].str != NULL; i++) {
+ if (nameRouteTypeString[i].type == type) {
+ return nameRouteTypeString[i].str;
+ }
+ }
+ trapIllegalValue(type, "Unknown type: %d", type);
+}
+
+CPINameRouteType
+cpiNameRouteType_FromString(const char *str)
+{
+ for (int i = 0; nameRouteTypeString[i].str != NULL; i++) {
+ if (strcasecmp(nameRouteTypeString[i].str, str) == 0) {
+ return nameRouteTypeString[i].type;
+ }
+ }
+ trapIllegalValue(type, "Unknown type: %s", str);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_NameRouteType.h b/libccnx-transport-rta/ccnx/api/control/cpi_NameRouteType.h
new file mode 100644
index 00000000..a0dca7cf
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_NameRouteType.h
@@ -0,0 +1,92 @@
+/*
+ * 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 cpi_NameRouteType.h
+ * @brief Specifies how a route should be matched
+ *
+ * NOTE: Only LONGEST_MATCH is currently implemented.
+ *
+ * A LONGEST_MATCH route is a normal CCNx route entry. It will match any Interest name that is equal to the route prefix
+ * or any Interest name that is equal to the router prefix and has additional name components. Each name component must be
+ * exactly equal on a component-by-component basis.
+ *
+ * An EXACT_MATCH route will not match any longer names. An Interest name must exactly match the route prefix.
+ *
+ * A Default route will be used if there are no other matches.
+ *
+ */
+
+#ifndef libccnx_cpi_NameRouteType_h
+#define libccnx_cpi_NameRouteType_h
+
+/**
+ * @typedef CPINameRouteType
+ * @abstract Enumerates the types of route entries
+ * @constant cpiNameRouteType_EXACT_MATCH Specifies an exact match route
+ * @constant cpiNameRouteType_LONGEST_MATCH Specifies a longest matching prefix entry (a normal CCNx route)
+ * @constant cpiNameRouteType_DEFAULT Specifies a default route that is used if no other entries match
+ */
+typedef enum {
+ cpiNameRouteType_EXACT_MATCH = 1,
+ cpiNameRouteType_LONGEST_MATCH = 2,
+ cpiNameRouteType_DEFAULT = 3
+} CPINameRouteType;
+
+/**
+ * Return the string representation of the specified `CPINameRouteType`.
+ *
+ * The returned string does not need to be freed.
+ *
+ * @param [in] type The type to represent as a string.
+ *
+ * @return The string representation of the specified 'CPINameRouteType'.
+ *
+ * Example:
+ * @code
+ * {
+ * CPINameRouteType type = cpiNameRouteType_LONGEST_MATCH;
+ *
+ * char *name = cpiNameRouteType_ToString(type);
+ *
+ * printf("NameRouteType is %s\n", name);
+ * }
+ * @endcode
+ *
+ * @see cpiNameRouteType_FromString
+ */
+const char *cpiNameRouteType_ToString(CPINameRouteType type);
+
+/**
+ * Given a string describing a `CPINameRouteType`, return the matching `CPINameRouteType`.
+ *
+ * If an invalid string is specified, the program will terminate with an IllegalValue exception.
+ * Possible values are: "EXACT", "LONGEST", and "DEFAULT".
+ *
+ * @param [in] str A pointer to a string representation of the desired `CPINameRouteType`.
+ *
+ * @return The `NameRouteType` matching the specified string.
+ *
+ * Example:
+ * @code
+ * {
+ * CPINameRouteType type = cpiNameRouteType_FromString("EXACT");
+ * }
+ * @endcode
+ *
+ * @see cpiNameRouteType_ToString
+ */
+CPINameRouteType cpiNameRouteType_FromString(const char *str);
+#endif // libccnx_cpi_NameRouteType_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_RouteEntry.c b/libccnx-transport-rta/ccnx/api/control/cpi_RouteEntry.c
new file mode 100644
index 00000000..0de5c915
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_RouteEntry.c
@@ -0,0 +1,466 @@
+/*
+ * 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 <ccnx/api/control/cpi_RouteEntry.h>
+#include <ccnx/api/control/controlPlaneInterface.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <limits.h>
+
+#include <LongBow/runtime.h>
+
+static const char *cpiPrefix = "PREFIX";
+static const char *cpiInterface = "INTERFACE";
+static const char *cpiFlags = "FLAGS";
+static const char *cpiLifetime = "LIFETIME";
+static const char *cpiNexthop = "NEXTHOP";
+static const char *cpiProtocol = "PROTOCOL";
+static const char *cpiRouteType = "ROUTETYPE";
+static const char *cpiCost = "COST";
+static const char *cpiSymbolic = "SYMBOLIC";
+
+struct cpi_route_entry {
+ bool hasInterfaceIndex;
+ unsigned interfaceIndex;
+
+ CCNxName *prefix;
+ char *symbolic;
+ CPIAddress *nexthop;
+ CPINameRouteProtocolType routingProtocol;
+ CPINameRouteType routeType;
+ unsigned cost;
+
+ bool hasLifetime;
+ struct timeval lifetime;
+};
+
+void
+cpiRouteEntry_Destroy(CPIRouteEntry **routeEntryPtr)
+{
+ assertNotNull(routeEntryPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*routeEntryPtr, "Parameter must dereference to non-null pointer");
+ CPIRouteEntry *route = *routeEntryPtr;
+
+ ccnxName_Release(&route->prefix);
+ if (route->nexthop) {
+ cpiAddress_Destroy(&route->nexthop);
+ }
+
+ if (route->symbolic) {
+ parcMemory_Deallocate((void **) &route->symbolic);
+ }
+
+ parcMemory_Deallocate((void **) &route);
+ *routeEntryPtr = NULL;
+}
+
+CPIRouteEntry *
+cpiRouteEntry_CreateRouteToSelf(const CCNxName *prefix)
+{
+ void *optionalLifetime = NULL;
+ void *nexthop = NULL;
+ unsigned cost = 0;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(ccnxName_Copy(prefix),
+ CPI_CURRENT_INTERFACE,
+ nexthop,
+ cpiNameRouteProtocolType_LOCAL,
+ cpiNameRouteType_LONGEST_MATCH,
+ optionalLifetime,
+ cost);
+ return route;
+}
+
+char *
+cpiRouteEntry_ToString(CPIRouteEntry *route)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcBufferComposer_Format(composer, "%6d %9.9s %7.7s %u ",
+ route->interfaceIndex,
+ cpiNameRouteProtocolType_ToString(route->routingProtocol),
+ cpiNameRouteType_ToString(route->routeType),
+ route->cost);
+
+ if (route->symbolic != NULL) {
+ parcBufferComposer_PutString(composer, route->symbolic);
+ } else {
+ parcBufferComposer_PutChar(composer, '-');
+ }
+
+ if (route->nexthop != NULL) {
+ cpiAddress_BuildString(cpiRouteEntry_GetNexthop(route), composer);
+ } else {
+ parcBufferComposer_PutChar(composer, '-');
+ }
+
+ if (route->hasLifetime) {
+#if __APPLE__
+ parcBufferComposer_Format(composer, " %ld.%06d ", route->lifetime.tv_sec, route->lifetime.tv_usec);
+#else
+ parcBufferComposer_Format(composer, " %ld.%06ld ", route->lifetime.tv_sec, route->lifetime.tv_usec);
+#endif
+ } else {
+ parcBufferComposer_Format(composer, " %8.8s ", "infinite");
+ }
+
+ char *ccnxName = ccnxName_ToString(cpiRouteEntry_GetPrefix(route));
+ parcBufferComposer_PutString(composer, ccnxName);
+
+ parcMemory_Deallocate((void **) &ccnxName);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ parcBufferComposer_Release(&composer);
+ return result;
+}
+
+CPIRouteEntry *
+cpiRouteEntry_Create(CCNxName *prefix,
+ unsigned interfaceIndex,
+ const CPIAddress *optionalNexthop,
+ CPINameRouteProtocolType routingProtocol,
+ CPINameRouteType routeType,
+ const struct timeval *optionalLifetime,
+ unsigned cost)
+{
+ assertNotNull(prefix, "Parameter prefix must be non-null");
+
+ CPIRouteEntry *route = parcMemory_AllocateAndClear(sizeof(CPIRouteEntry));
+ assertNotNull(route, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIRouteEntry));
+ route->prefix = prefix;
+ route->symbolic = NULL;
+ route->interfaceIndex = interfaceIndex;
+ route->hasInterfaceIndex = true;
+ route->nexthop = optionalNexthop != NULL ? cpiAddress_Copy(optionalNexthop) : NULL;
+ route->routingProtocol = routingProtocol;
+ route->routeType = routeType;
+ route->cost = cost;
+
+ if (optionalLifetime) {
+ route->hasLifetime = true;
+ route->lifetime = *optionalLifetime;
+ } else {
+ route->hasLifetime = false;
+ route->lifetime = (struct timeval) { .tv_sec = INT_MAX, .tv_usec = 0 };
+ }
+
+ return route;
+}
+
+CPIRouteEntry *
+cpiRouteEntry_CreateSymbolic(CCNxName *prefix,
+ const char *symbolicName,
+ CPINameRouteProtocolType routingProtocol,
+ CPINameRouteType routeType,
+ const struct timeval *optionalLifetime,
+ unsigned cost)
+{
+ assertNotNull(prefix, "Parameter prefix must be non-null");
+
+ CPIRouteEntry *route = parcMemory_AllocateAndClear(sizeof(CPIRouteEntry));
+ assertNotNull(route, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIRouteEntry));
+ route->prefix = prefix;
+ route->symbolic = parcMemory_StringDuplicate(symbolicName, strlen(symbolicName));
+ route->interfaceIndex = UINT32_MAX;
+ route->hasInterfaceIndex = false;
+ route->nexthop = NULL;
+ route->routingProtocol = routingProtocol;
+ route->routeType = routeType;
+ route->cost = cost;
+
+ if (optionalLifetime) {
+ route->hasLifetime = true;
+ route->lifetime = *optionalLifetime;
+ } else {
+ route->hasLifetime = false;
+ route->lifetime = (struct timeval) { .tv_sec = INT_MAX, .tv_usec = 0 };
+ }
+
+ return route;
+}
+
+
+CPIRouteEntry *
+cpiRouteEntry_Copy(const CPIRouteEntry *original)
+{
+ assertNotNull(original, "Parameter a must be non-null");
+ CPIRouteEntry *copy;
+
+ if (original->hasInterfaceIndex) {
+ copy = cpiRouteEntry_Create(
+ ccnxName_Copy(original->prefix),
+ original->interfaceIndex,
+ (original->nexthop ? original->nexthop : NULL),
+ original->routingProtocol,
+ original->routeType,
+ (original->hasLifetime ? &original->lifetime : NULL),
+ original->cost);
+
+ if (original->symbolic) {
+ copy->symbolic = parcMemory_StringDuplicate(original->symbolic, strlen(original->symbolic));
+ }
+ } else {
+ copy = cpiRouteEntry_CreateSymbolic(
+ ccnxName_Copy(original->prefix),
+ original->symbolic,
+ original->routingProtocol,
+ original->routeType,
+ (original->hasLifetime ? &original->lifetime : NULL),
+ original->cost);
+ }
+ return copy;
+}
+
+void
+cpiRouteEntry_SetInterfaceIndex(CPIRouteEntry *route, unsigned interfaceIndex)
+{
+ assertNotNull(route, "Parameter a must be non-null");
+ route->interfaceIndex = interfaceIndex;
+ route->hasInterfaceIndex = true;
+}
+
+
+bool
+cpiRouteEntry_Equals(const CPIRouteEntry *a, const CPIRouteEntry *b)
+{
+ assertNotNull(a, "Parameter a must be non-null");
+ assertNotNull(b, "Parameter b must be non-null");
+ if (a == b) {
+ return true;
+ }
+
+ if (a->interfaceIndex == b->interfaceIndex) {
+ if (a->routeType == b->routeType) {
+ if (a->routingProtocol == b->routingProtocol) {
+ if (a->cost == b->cost) {
+ if (ccnxName_Equals(a->prefix, b->prefix)) {
+ if (cpiAddress_Equals(a->nexthop, b->nexthop)) {
+ if (a->hasLifetime == b->hasLifetime) {
+ if (timercmp(&a->lifetime, &b->lifetime, ==)) {
+ if (a->symbolic == b->symbolic || (a->symbolic != NULL && b->symbolic != NULL && strcasecmp(a->symbolic, b->symbolic) == 0)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+const CCNxName *
+cpiRouteEntry_GetPrefix(const CPIRouteEntry *route)
+{
+ assertNotNull(route, "Parameter must be non-null");
+ return route->prefix;
+}
+
+unsigned
+cpiRouteEntry_GetInterfaceIndex(const CPIRouteEntry *route)
+{
+ assertNotNull(route, "Parameter must be non-null");
+ return route->interfaceIndex;
+}
+
+const CPIAddress *
+cpiRouteEntry_GetNexthop(const CPIRouteEntry *route)
+{
+ assertNotNull(route, "Parameter must be non-null");
+ return route->nexthop;
+}
+
+bool
+cpiRouteEntry_HasLifetime(const CPIRouteEntry *route)
+{
+ assertNotNull(route, "Parameter must be non-null");
+ return route->hasLifetime;
+}
+
+struct timeval
+cpiRouteEntry_GetLifetime(const CPIRouteEntry *route)
+{
+ assertNotNull(route, "Parameter must be non-null");
+ return route->lifetime;
+}
+
+CPINameRouteProtocolType
+cpiRouteEntry_GetRouteProtocolType(const CPIRouteEntry *route)
+{
+ assertNotNull(route, "Parameter must be non-null");
+ return route->routingProtocol;
+}
+
+CPINameRouteType
+cpiRouteEntry_GetRouteType(const CPIRouteEntry *route)
+{
+ assertNotNull(route, "Parameter must be non-null");
+ return route->routeType;
+}
+
+unsigned
+cpiRouteEntry_GetCost(const CPIRouteEntry *route)
+{
+ assertNotNull(route, "Parameter must be non-null");
+ return route->cost;
+}
+
+const char *
+cpiRouteEntry_GetSymbolicName(const CPIRouteEntry *route)
+{
+ assertNotNull(route, "Parameter must be non-null");
+ return route->symbolic;
+}
+
+PARCJSON *
+cpiRouteEntry_ToJson(const CPIRouteEntry *route)
+{
+ assertNotNull(route, "Parameter must be non-null");
+
+ PARCJSON *routeJson = parcJSON_Create();
+ char *uri = ccnxName_ToString(route->prefix);
+ parcJSON_AddString(routeJson, cpiPrefix, uri);
+ parcMemory_Deallocate((void **) &uri);
+
+ if (route->symbolic) {
+ parcJSON_AddString(routeJson, cpiSymbolic, route->symbolic);
+ }
+
+ if (route->hasInterfaceIndex) {
+ parcJSON_AddInteger(routeJson, cpiInterface, route->interfaceIndex);
+ }
+
+ parcJSON_AddInteger(routeJson, cpiFlags, 0);
+
+ if (route->nexthop) {
+ // some registrations can have NULL nexthop, its ok
+ PARCJSON *json = cpiAddress_ToJson(route->nexthop);
+ parcJSON_AddObject(routeJson, cpiNexthop, json);
+ parcJSON_Release(&json);
+ }
+
+ parcJSON_AddString(routeJson, cpiProtocol, cpiNameRouteProtocolType_ToString(route->routingProtocol));
+ parcJSON_AddString(routeJson, cpiRouteType, cpiNameRouteType_ToString(route->routeType));
+ parcJSON_AddInteger(routeJson, cpiCost, route->cost);
+
+ if (route->hasLifetime) {
+ PARCJSONArray *lifetimeJson = parcJSONArray_Create();
+ PARCJSONValue *value = parcJSONValue_CreateFromInteger(route->lifetime.tv_sec);
+ parcJSONArray_AddValue(lifetimeJson, value);
+ parcJSONValue_Release(&value);
+ value = parcJSONValue_CreateFromInteger(route->lifetime.tv_usec);
+ parcJSONArray_AddValue(lifetimeJson, value);
+ parcJSONValue_Release(&value);
+ parcJSON_AddArray(routeJson, cpiLifetime, lifetimeJson);
+ parcJSONArray_Release(&lifetimeJson);
+ }
+
+ return routeJson;
+}
+
+CPIRouteEntry *
+cpiRouteEntry_FromJson(PARCJSON *json)
+{
+ assertNotNull(json, "Parameter json must be non-null");
+ PARCJSON *routeJson = json;
+
+ PARCJSONValue *value = parcJSON_GetValueByName(routeJson, cpiPrefix);
+ assertNotNull(value, "Couldn't locate tag %s in: %s", cpiPrefix, parcJSON_ToString(json));
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ CCNxName *prefix = ccnxName_CreateFromCString(parcBuffer_Overlay(sBuf, 0));
+
+ const char *symbolicName = NULL;
+ value = parcJSON_GetValueByName(routeJson, cpiSymbolic);
+ if (value) {
+ sBuf = parcJSONValue_GetString(value);
+ symbolicName = parcBuffer_Overlay(sBuf, 0);
+ }
+
+ bool hasInterfaceIndex = false;
+ unsigned interfaceIndex = UINT32_MAX;
+ value = parcJSON_GetValueByName(routeJson, cpiInterface);
+ if (value) {
+ hasInterfaceIndex = true;
+ interfaceIndex = (unsigned) parcJSONValue_GetInteger(value);
+ }
+
+ CPIAddress *nexthop = NULL;
+ value = parcJSON_GetValueByName(routeJson, cpiNexthop);
+ if (value != NULL) {
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Json key %s wrong type in json %s",
+ cpiNexthop,
+ parcJSON_ToString(json));
+ PARCJSON *nexthopJson = parcJSONValue_GetJSON(value);
+ nexthop = cpiAddress_CreateFromJson(nexthopJson);
+ }
+
+ value = parcJSON_GetValueByName(routeJson, cpiProtocol);
+ sBuf = parcJSONValue_GetString(value);
+ char *valueString = parcBuffer_Overlay(sBuf, 0);
+ CPINameRouteProtocolType routingProtocol = cpiNameRouteProtocolType_FromString(valueString);
+
+ value = parcJSON_GetValueByName(routeJson, cpiRouteType);
+ sBuf = parcJSONValue_GetString(value);
+ valueString = parcBuffer_Overlay(sBuf, 0);
+ CPINameRouteType routingType = cpiNameRouteType_FromString(valueString);
+
+ value = parcJSON_GetValueByName(routeJson, cpiCost);
+ unsigned cost = (unsigned) parcJSONValue_GetInteger(value);
+
+ value = parcJSON_GetValueByName(routeJson, cpiLifetime);
+ struct timeval *lifetime = NULL;
+
+ struct timeval actual_time = { 0, 0 };
+ if (value != NULL) {
+ assertTrue(parcJSONValue_IsArray(value),
+ "Json key %s wrong typein json %s",
+ cpiNexthop,
+ parcJSON_ToString(json));
+ PARCJSONArray *lifetimeJson = parcJSONValue_GetArray(value);
+
+ actual_time.tv_sec = parcJSONValue_GetInteger(parcJSONArray_GetValue(lifetimeJson, 0));
+ actual_time.tv_usec = (int) parcJSONValue_GetInteger(parcJSONArray_GetValue(lifetimeJson, 1));
+
+ lifetime = &actual_time;
+ }
+
+
+ // == we're now ready to create the object
+ CPIRouteEntry *route;
+ if (symbolicName) {
+ route = cpiRouteEntry_CreateSymbolic(prefix, symbolicName, routingProtocol, routingType, lifetime, cost);
+ if (hasInterfaceIndex) {
+ cpiRouteEntry_SetInterfaceIndex(route, interfaceIndex);
+ }
+ } else {
+ route = cpiRouteEntry_Create(prefix, interfaceIndex, nexthop, routingProtocol, routingType, lifetime, cost);
+ }
+
+ if (nexthop) {
+ cpiAddress_Destroy(&nexthop);
+ }
+
+ return route;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_RouteEntry.h b/libccnx-transport-rta/ccnx/api/control/cpi_RouteEntry.h
new file mode 100644
index 00000000..79aa2cfb
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_RouteEntry.h
@@ -0,0 +1,587 @@
+/*
+ * 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 cpi_RouteEntry.h
+ * @brief A representation of a route entry.
+ *
+ * A CCNx route consists of the tuple (prefix, interfaceIndex, [nextHop], routingProtocol, routeType, [lifetime], cost).
+ *
+ * The "prefix" is the CCNx name in question. If the "routeType" is Exact Match then the prefix must exactly match an Interest Name.
+ * If the routeType is Longest Prefix (a normal CCNx route), then it will match any equal or longer Interest name. If the routeType
+ * is Default, then it will match any equal or longer name if no other route matched.
+ *
+ * The interfaceIndex (a.k.a Connection ID) is the entry in the forwarder's connection table to use to forward the Interest.
+ * Newer commands use a symblic name instead of a connection id. A symbolic name is an alpha followed by alphanums. It is specified
+ * when creating a tunnel or connection. Auto-added connections inside the forwarder will only have a connection id.
+ *
+ * The optional NextHop specifies a link-specific nexthop identifier on the outbound interfaceIndex. This could be used, for example, with
+ * an Ethernet link. The Connection table entry could be the CCNx Group address entry (i.e. any packet sent to it will go out on the
+ * CCNx Ethernet group address) and by specifying the optional NextHop give a specific unicast MAC address.
+ *
+ * routingProtocol identifies the protocol that created the route entry.
+ *
+ * routeType, as described above, specifies how the prefix matches an Interest name.
+ *
+ * lifetime specified how long the router will keep the forwarding entry active. The routing protocol must refresh the entry
+ * to keep it alive.
+ *
+ * cost reflects the route cost. Some forwarding strategies might use the cost information to make a decision, but it is not
+ * used by the normal unicast or multicast strategies.
+ *
+ */
+#ifndef libccnx_cpi_RouteEntry_h
+#define libccnx_cpi_RouteEntry_h
+
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/api/control/cpi_Address.h>
+#include <ccnx/api/control/cpi_NameRouteProtocolType.h>
+#include <ccnx/api/control/cpi_NameRouteType.h>
+
+#include <parc/algol/parc_JSON.h>
+
+struct cpi_route_entry;
+/**
+ * @typedef CPIRouteEntry
+ * @brief A representation of a route entry.
+ */
+typedef struct cpi_route_entry CPIRouteEntry;
+
+/**
+ * Creates a route entry, takes ownership of the name object
+ *
+ * @param [in] prefix for the route, takes ownership of this memory.
+ * @param [in] optionalNexthop may be NULL, represents where the FIB points.
+ * @param [in] routingProtocol represents the algorithm used to create the route entry.
+ * @param [in] routeType selects how the FIB matches the prefix.
+ * @param [in] optionalLifetime is how long the FIB entry stays valid unless refreshed.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a valid CPIRouteEntry instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * unsigned ifidx = 55;
+ * CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ * struct timeval lifetime = { 3600, 0 };
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ * }
+ * @endcode
+ *
+ * @see cpiRouteEntry_Destroy
+ */
+CPIRouteEntry *cpiRouteEntry_Create(CCNxName *prefix, unsigned interfaceIndex, const CPIAddress *optionalNexthop,
+ CPINameRouteProtocolType routingProtocol, CPINameRouteType routeType,
+ const struct timeval *optionalLifetime, unsigned cost);
+
+
+/**
+ * Creates a route entry, takes ownership of the name object
+ *
+ * @param [in] prefix for the route, takes ownership of this memory.
+ * @param [in] symbolicName The symbolic name of the connection or tunnel to use.
+ * @param [in] routingProtocol represents the algorithm used to create the route entry.
+ * @param [in] routeType selects how the FIB matches the prefix.
+ * @param [in] optionalLifetime is how long the FIB entry stays valid unless refreshed.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a valid CPIRouteEntry instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ * struct timeval lifetime = { 3600, 0 };
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_CreateSymbolic(prefix, "tun0", cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ * }
+ * @endcode
+ *
+ * @see cpiRouteEntry_Destroy
+ */
+CPIRouteEntry *cpiRouteEntry_CreateSymbolic(CCNxName *prefix, const char *symbolicName,
+ CPINameRouteProtocolType routingProtocol, CPINameRouteType routeType,
+ const struct timeval *optionalLifetime, unsigned cost);
+
+/**
+ * Create a CPIRouteEntry instance that represents a route to this node.
+ *
+ * @param [in] name A CCNxName instance representing the name to route to this node.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to an allocated CPIRouteEntry instance that must be deallocated via cpiRouteEntry_Destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_FromCString("lci:/a/b");
+ * CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(prefix);
+ * ccnxName_Release(&prefix);
+ * }
+ * @endcode
+ *
+ * @see cpiRouteEntry_Destroy
+ */
+CPIRouteEntry *cpiRouteEntry_CreateRouteToSelf(const CCNxName *name);
+
+/**
+ * Deallocate and destroy a CPIRouteEntry instance.
+ *
+ * @param [in] routeEntryPtr A pointer to a pointer to a valid CPIRouteEntry instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_FromCString("lci:/a/b");
+ * CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(prefix);
+ * ccnxName_Release(&prefix);
+ *
+ * cpiRouteEntry_Destroy(&route);
+ * }
+ * @endcode
+ */
+void cpiRouteEntry_Destroy(CPIRouteEntry **routeEntryPtr);
+
+/**
+ * Copy a CPIRouteEntry instance.
+ *
+ * Creates a deep copy of the Route Entry.
+ *
+ * @param [in] routeEntry A pointer to a valid CPIRouteEntry instance.
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a valid CPIRouteEntry instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_FromCString("lci:/a/b");
+ * CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(prefix);
+ * ccnxName_Release(&prefix);
+ *
+ * CPIRouteEntry *copy = cpiRouteEntry_Copy(route);
+ * cpiRouteEntry_Destroy(&route);
+ * cpiRouteEntry_Destroy(&copy);
+ * }
+ * @endcode
+ */
+CPIRouteEntry *cpiRouteEntry_Copy(const CPIRouteEntry *routeEntry);
+
+/**
+ * Determine if two `CPIRouteEntry` instances are equal.
+ *
+ * The following equivalence relations on non-null `CPIRouteEntry` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `cpiRouteEntry_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `cpiRouteEntry_Equals(x, y)` must return true if and only if
+ * `cpiRouteEntry_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiRouteEntry_Equals(x, y)` returns true and
+ * `cpiRouteEntry_Equals(y, z)` returns true,
+ * then `cpiRouteEntry_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `cpiRouteEntry_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `cpiRouteEntry_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] a A pointer to a `CPIRouteEntry` instance.
+ * @param [in] b A pointer to a `CPIRouteEntry` instance.
+ *
+ * @return true `CPIRouteEntry` x and y are equal.
+ * @return false `CPIRouteEntry` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIRouteEntry *bufferA = parcBuffer_Allocate(10);
+ * CPIRouteEntry *bufferB = parcBuffer_Allocate(10);
+ *
+ * CCNxName *prefixA = ccnxName_FromCString("lci:/a/b");
+ * CPIRouteEntry *routeA = cpiRouteEntry_CreateRouteToSelf(prefixA);
+ * ccnxName_Release(&prefixA);
+ *
+ * CCNxName *prefixB = ccnxName_FromCString("lci:/a/b");
+ * CPIRouteEntry *routeB = cpiRouteEntry_CreateRouteToSelf(prefixB);
+ * ccnxName_Release(&prefixB);
+ *
+ * if (cpiRouteEntry_Equals(routeA, routeB)) {
+ * printf("Routes are equal.\n");
+ * } else {
+ * printf("Routes are NOT equal.\n");
+ * }
+ * cpiRouteEntry_Destroy(&bufferA);
+ * cpiRouteEntry_Destroy(&bufferB);
+ * }
+ * @endcode
+ */
+bool cpiRouteEntry_Equals(const CPIRouteEntry *a, const CPIRouteEntry *b);
+
+/**
+ * Set the interface index for the given `CPIRouteEntry`
+ *
+ * @param [in] route A pointer to a `CPIRouteEntry` instance.
+ * @param [in] interfaceIndex The interface index value.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * unsigned ifidx = -1; // unknown
+ * CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ * struct timeval *lifetimePtr = NULL;
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetimePtr, cost);
+ *
+ * // once we know an interface index, set it
+ * cpiRouteEntry_SetInterfaceIndex(route, 55);
+ * }
+ * @endcode
+ */
+void cpiRouteEntry_SetInterfaceIndex(CPIRouteEntry *route, unsigned interfaceIndex);
+
+/**
+ * Get the name of the routing prefix in the given `CPIRouteEntry` instance.
+ *
+ * @param [in] route A pointer to a `CPIRouteEntry` instance.
+ *
+ * @return A pointer to the name of the routing prefix in the given `CPIRouteEntry` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * unsigned ifidx = -1; // unknown
+ * CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ * struct timeval *lifetimePtr = NULL;
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetimePtr, cost);
+ *
+ * CCNxName *testPrefix = cpiRouteEntry_GetPrefix(route);
+ * assertTrue(ccnxName_Equals(prefix, testPrefix), "The prefix of the route should be equal to what was set.");
+ * }
+ * @endcode
+ */
+const CCNxName *cpiRouteEntry_GetPrefix(const CPIRouteEntry *route);
+
+/**
+ * Get the interface index in the given `CPIRouteEntry`
+ *
+ * @param [in] route A pointer to a `CPIRouteEntry` instance.
+ *
+ * @return The interface index in the given `CPIRouteEntry`
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * unsigned ifidx = 55;
+ * CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ * struct timeval *lifetimePtr = NULL;
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetimePtr, cost);
+ *
+ * assertTrue(cpiRouteEntry_GetInterfaceIndex(route), ifidx, "Route interface should be equal to what was set.");
+ * }
+ * @endcode
+ */
+unsigned cpiRouteEntry_GetInterfaceIndex(const CPIRouteEntry *route);
+
+/**
+ * Get the CPIAddress of the next hop for the given CPIRouteEntry instance.
+ *
+ * The nexthop may be used for certain types of routes to override the destination address. This might be used
+ * with some Ethernet routes, but is not necessary if one creates a cpiConnectionEthernet to the specific destination.
+ *
+ * @param [in] route A pointer to a `CPIRouteEntry` instance.
+ *
+ * @return non-null A pointer to a valid CPIAddress.
+ * @return null No nexthop was specified when the route was created.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * unsigned ifidx = 55;
+ * CPIAddress *nexthop = NULL;
+ * struct timeval lifetime = { 3600, 0 };
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ *
+ * assertNull(cpiRouteEntry_GetNexthop(route), "Route has no nexthop");
+ * }
+ * @endcode
+ */
+const CPIAddress *cpiRouteEntry_GetNexthop(const CPIRouteEntry *route);
+
+/**
+ * Determines if the Route Entry has a lifetime
+ *
+ * Returns true if a lifetime is specified for the route
+ *
+ * @param [in] route A non-null pointer to a CPIRouteEntry instance.
+ *
+ * @return true if the given CPIRouteEntry has a lifetime.
+ * @return false if it does not have a lifetime
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * unsigned ifidx = 55;
+ * CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ * struct timeval *lifetimePtr = NULL;
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetimePtr, cost);
+ *
+ * assertFalse(cpiRouteEntry_HasLifetime(route), "NULL lifetimePtr should return false");
+ * }
+ * @endcode
+ *
+ * @see cpiRouteEntry_GetLifetime()
+ */
+bool cpiRouteEntry_HasLifetime(const CPIRouteEntry *route);
+
+/**
+ * Returns the lifetime associated with a route
+ *
+ * The return value is undefined is the route does not have a lifetime. See cpiRouteEntry_HasLifetime().
+ *
+ * @param [in] route A non-null pointer to a CPIRouteEntry instance.
+ *
+ * @return The route lifetime
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * unsigned ifidx = 55;
+ * CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ * struct timeval lifetime = { 3600, 0 };
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ * struct timeval testLifetime = cpiRouteEntry_GetLifetime(route);
+ * assertTrue(timercmp(&lifetime, &testLifetime, ==), "Lifetimes should be equal");
+ * }
+ * @endcode
+ */
+struct timeval cpiRouteEntry_GetLifetime(const CPIRouteEntry *route);
+
+/**
+ * Returns the protocol identifer that created the route
+ *
+ * The ProtocolType identifies who created the route, such as a static route (administratively created) or
+ * a routing protocol such as ACRON.
+ *
+ * @param [in] route A non-null pointer to a CPIRouteEntry instance.
+ *
+ * @return `CPINameRouteProtocolType` the protocol specified when the route was created
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * unsigned ifidx = 55;
+ * CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ * struct timeval lifetime = { 3600, 0 };
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ *
+ * CPINameRouteProtocolType protocol = cpiRouteEntry_GetRouteProtocolType(route);
+ * assertTrue(protocol == cpiNameRouteProtocolType_STATIC, "Route is of STATIC protocol");
+ * }
+ * @endcode
+ */
+CPINameRouteProtocolType cpiRouteEntry_GetRouteProtocolType(const CPIRouteEntry *route);
+
+/**
+ * Returns the type of route
+ *
+ * The route type determines how an Interest name matches the route.
+ *
+ * @param [in] route An allocated route entry
+ *
+ * @return `CPINameRouteType` The route type specified when the route entry was created
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * unsigned ifidx = 55;
+ * CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ * struct timeval lifetime = { 3600, 0 };
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ *
+ * CPINameRouteType type = cpiRouteEntry_GetRouteType(route);
+ * assertTrue(type == cpiNameRouteType_LONGEST_MATCH, "Route is of LONGEST_MATCH type");
+ * }
+ * @endcode
+ */
+CPINameRouteType cpiRouteEntry_GetRouteType(const CPIRouteEntry *route);
+
+/**
+ * Get the "cost" value of the given `CPIRouteEntry`
+ *
+ * The cost may be used by some forwarding strategies to pick between alternatives.
+ *
+ * @param [in] route A pointer to a valid `CPIRouteEntry`
+ *
+ * @return The "cost" value of the given `CPIRouteEntry`
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName * prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * unsigned ifidx = 55;
+ * CPIAddress * nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ * struct timeval lifetime = { 3600, 0 };
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ *
+ * unsigned testCost = cpiRouteEntry_GetCost(route);
+ * assertTrue(cost == testCost, "Route cost should be 200");
+ * }
+ * @endcode
+ */
+unsigned cpiRouteEntry_GetCost(const CPIRouteEntry *route);
+
+/**
+ * Create a `PARCJSON` representation of the given `CPIRouteEntry` instance.
+ *
+ * @param [in] route A pointer to a valid `PARCJSON` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to an allocated `CPIRouteEntry` instance that must be deallocated via `cpiRouteEntry_Destroy`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * unsigned ifidx = 55;
+ * CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ * struct timeval lifetime = { 3600, 0 };
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ *
+ * PARCJSON *json = cpiRouteEntry_ToJson(route);
+ *
+ * ...
+ * }
+ * @endcode
+ *
+ * @see cpiRouteEntry_FromJson
+ */
+PARCJSON *cpiRouteEntry_ToJson(const CPIRouteEntry *route);
+
+/**
+ * Create a new `CPIRouteEntry` instance from the given `PARCJSON` instance.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to an allocated `CPIRouteEntry` instance that must be deallocated via `cpiRouteEntry_Destroy`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * unsigned ifidx = 55;
+ * CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ * struct timeval lifetime = { 3600, 0 };
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ *
+ * PARCJSON *json = cpiRouteEntry_ToJson(route);
+ *
+ * ...
+ *
+ * CPIRouteEntry *newRoute = cpiRouteEntry_FromJson(json);
+ * // route and newRoute will be equal
+ * }
+ * @endcode
+ *
+ * @see cpiRouteEntry_ToJson
+ */
+CPIRouteEntry *cpiRouteEntry_FromJson(PARCJSON *json);
+
+/**
+ * Produce a nul-terminated string representation of the specified instance.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] buffer 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 {@link parcMemory_Deallocate}.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ * unsigned ifidx = 55;
+ * CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ * struct timeval lifetime = { 3600, 0 };
+ * unsigned cost = 200;
+ *
+ * CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ *
+ * printf("Route: %s\n", cpiRouteEntry_ToString(route));
+ * }
+ * @endcode
+ */
+char *cpiRouteEntry_ToString(CPIRouteEntry *route);
+
+/**
+ * Returns the symblic name associated with the route entry, may be NULL
+ *
+ * A symbolic name is not always associated with a route entry.
+ *
+ * @param [in] route An allocted CPIRouteEntry
+ *
+ * @return non-null The symbolic name associated with the route entry
+ * @return null No symbolic name is associated with the route entry.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *cpiRouteEntry_GetSymbolicName(const CPIRouteEntry *route);
+
+#endif // libccnx_cpi_RouteEntry_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_RouteEntryList.c b/libccnx-transport-rta/ccnx/api/control/cpi_RouteEntryList.c
new file mode 100644
index 00000000..c13b3f0d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_RouteEntryList.c
@@ -0,0 +1,163 @@
+/*
+ * 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_ArrayList.h>
+
+#include <ccnx/api/control/cpi_RouteEntryList.h>
+#include <LongBow/runtime.h>
+
+struct cpi_route_entry_list {
+ PARCArrayList *listOfRouteEntries;
+};
+
+/**
+ * PARCArrayList entry destroyer
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+_cpiRouteEntryList_ArrayDestroyer(void **voidPtr)
+{
+ CPIRouteEntry **entryPtr = (CPIRouteEntry **) voidPtr;
+ cpiRouteEntry_Destroy(entryPtr);
+}
+
+CPIRouteEntryList *
+cpiRouteEntryList_Create()
+{
+ CPIRouteEntryList *list = parcMemory_AllocateAndClear(sizeof(CPIRouteEntryList));
+ assertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIRouteEntryList));
+ list->listOfRouteEntries = parcArrayList_Create(_cpiRouteEntryList_ArrayDestroyer);
+ return list;
+}
+
+void
+cpiRouteEntryList_Destroy(CPIRouteEntryList **listPtr)
+{
+ assertNotNull(listPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*listPtr, "Parameter must dereference to non-null pointer");
+ CPIRouteEntryList *list = *listPtr;
+ parcArrayList_Destroy(&list->listOfRouteEntries);
+ parcMemory_Deallocate((void **) &list);
+ *listPtr = NULL;
+}
+
+void
+cpiRouteEntryList_Append(CPIRouteEntryList *list, CPIRouteEntry *entry)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ assertNotNull(entry, "Parameter entry must be non-null");
+
+ parcArrayList_Add(list->listOfRouteEntries, (PARCObject *) entry);
+}
+
+size_t
+cpiRouteEntryList_Length(const CPIRouteEntryList *list)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ return parcArrayList_Size(list->listOfRouteEntries);
+}
+
+CPIRouteEntry *
+cpiRouteEntryList_Get(CPIRouteEntryList *list, size_t index)
+{
+ assertNotNull(list, "Parameter list must be non-null");
+ CPIRouteEntry *original = (CPIRouteEntry *) parcArrayList_Get(list->listOfRouteEntries, index);
+ return cpiRouteEntry_Copy(original);
+}
+
+
+bool
+cpiRouteEntryList_Equals(const CPIRouteEntryList *a, const CPIRouteEntryList *b)
+{
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (parcArrayList_Size(a->listOfRouteEntries) == parcArrayList_Size(b->listOfRouteEntries)) {
+ size_t length = parcArrayList_Size(a->listOfRouteEntries);
+ for (size_t i = 0; i < length; i++) {
+ CPIRouteEntry *route_a = (CPIRouteEntry *) parcArrayList_Get(a->listOfRouteEntries, i);
+ CPIRouteEntry *route_b = (CPIRouteEntry *) parcArrayList_Get(b->listOfRouteEntries, i);
+ if (!cpiRouteEntry_Equals(route_a, route_b)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+const char cpi_RouteEntryList[] = "Routes";
+
+PARCJSON *
+cpiRouteEntryList_ToJson(const CPIRouteEntryList *list)
+{
+ assertNotNull(list, "Parameter must be non-null");
+
+ PARCJSONArray *routeList = parcJSONArray_Create();
+
+ size_t length = parcArrayList_Size(list->listOfRouteEntries);
+ for (size_t i = 0; i < length; i++) {
+ CPIRouteEntry *route = (CPIRouteEntry *) parcArrayList_Get(list->listOfRouteEntries, i);
+ PARCJSON *json = cpiRouteEntry_ToJson(route);
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ parcJSON_Release(&json);
+ parcJSONArray_AddValue(routeList, value);
+ parcJSONValue_Release(&value);
+ }
+
+ PARCJSON *result = parcJSON_Create();
+ parcJSON_AddArray(result, cpi_RouteEntryList, routeList);
+ parcJSONArray_Release(&routeList);
+
+ return result;
+}
+
+CPIRouteEntryList *
+cpiRouteEntryList_FromJson(PARCJSON *json)
+{
+ assertNotNull(json, "Parameter must be non-null");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpi_RouteEntryList);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpi_RouteEntryList,
+ parcJSON_ToString(json));
+ PARCJSONArray *routeList = parcJSONValue_GetArray(value);
+
+ CPIRouteEntryList *list = cpiRouteEntryList_Create();
+
+ size_t length = parcJSONArray_GetLength(routeList);
+ for (size_t i = 0; i < length; i++) {
+ PARCJSONValue *value = parcJSONArray_GetValue(routeList, i);
+ PARCJSON *routeJson = parcJSONValue_GetJSON(value);
+ CPIRouteEntry *route = cpiRouteEntry_FromJson(routeJson);
+ cpiRouteEntryList_Append(list, route);
+ }
+
+ return list;
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_RouteEntryList.h b/libccnx-transport-rta/ccnx/api/control/cpi_RouteEntryList.h
new file mode 100644
index 00000000..049cdc97
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_RouteEntryList.h
@@ -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.
+ */
+
+/**
+ * @file cpi_RouteEntryList.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_cpi_RouteEntryList_h
+#define libccnx_cpi_RouteEntryList_h
+
+struct cpi_route_entry_list;
+typedef struct cpi_route_entry_list CPIRouteEntryList;
+
+#include <ccnx/api/control/cpi_RouteEntry.h>
+
+CPIRouteEntryList *cpiRouteEntryList_Create();
+void cpiRouteEntryList_Destroy(CPIRouteEntryList **listPtr);
+
+/**
+ * Adds a route entry to the list.
+ *
+ * Appends <code>entry</code> to the list. Takes ownership of the entry
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void cpiRouteEntryList_Append(CPIRouteEntryList *list, CPIRouteEntry *entry);
+
+/**
+ * Determine if two CPIRouteEntryList instances are equal.
+ *
+ * Two CPIRouteEntryList instances are equal if, and only if,
+ * * ...
+ *
+ * The following equivalence relations on non-null `CPIRouteEntryList` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `CPIRouteEntryList_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `cpiRouteEntryList_Equals(x, y)` must return true if and only if
+ * `cpiRouteEntryList_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `cpiRouteEntryList_Equals(x, y)` returns true and
+ * `cpiRouteEntryList_Equals(y, z)` returns true,
+ * then `cpiRouteEntryList_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `cpiRouteEntryList_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `cpiRouteEntryList_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `CPIRouteEntryList` instance.
+ * @param b A pointer to a `CPIRouteEntryList` instance.
+ * @return true if the two `CPIRouteEntryList` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CPIRouteEntryList *a = cpiRouteEntryList_Create();
+ * CPIRouteEntryList *b = cpiRouteEntryList_Create();
+ *
+ * if (cpiRouteEntryList_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool cpiRouteEntryList_Equals(const CPIRouteEntryList *a, const CPIRouteEntryList *b);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+size_t cpiRouteEntryList_Length(const CPIRouteEntryList *list);
+
+/**
+ * Returns a reference counted copy of the route entry.
+ *
+ * Caller must destroy the returned value.
+ * Will assert if you go beyond the end of the list.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CPIRouteEntry *cpiRouteEntryList_Get(CPIRouteEntryList *list, size_t index);
+
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *cpiRouteEntryList_ToJson(const CPIRouteEntryList *list);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CPIRouteEntryList *cpiRouteEntryList_FromJson(PARCJSON *json);
+#endif // libccnx_cpi_RouteEntryList_h
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_private.h b/libccnx-transport-rta/ccnx/api/control/cpi_private.h
new file mode 100644
index 00000000..e13d347d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/cpi_private.h
@@ -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.
+ */
+
+/**
+ * @file cpi_private.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef libccnx_cpi_private_h
+#define libccnx_cpi_private_h
+
+uint64_t cpi_GetNextSequenceNumber(void);
+
+/**
+ * Wrap the operation in a CPI_REQUEST and add sequence number
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return JSON "{ CPI_REQUEST: { SEQUENCE:number key: { operation } }}"
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *cpi_CreateRequest(const char *key, PARCJSON *operation);
+
+/**
+ * <#OneLineDescription#>
+ *
+ * INPUT: "{ CPI_REQUEST: { SEQUENCE:number key: { operation } }}"
+ * OUTPUT: "{ key : { operation } }"
+ *
+ * Example: "{ REGISTER : { <code>cpiRoute_ToJson()</code> } }"
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSONPair *cpi_ParseRequest(PARCJSON *request);
+#endif // libccnx_cpi_private_h
diff --git a/libccnx-transport-rta/ccnx/api/control/test/.gitignore b/libccnx-transport-rta/ccnx/api/control/test/.gitignore
new file mode 100644
index 00000000..f6caadab
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/.gitignore
@@ -0,0 +1,24 @@
+test_controlPlaneInterface
+test_cpi_Acks
+test_cpi_Address
+test_cpi_AddressList
+test_cpi_CancelFlow
+test_cpi_Connection
+test_cpi_ControlFacade
+test_cpi_ControlMessage
+test_cpi_ConnectionEthernet
+test_cpi_ConnectionList
+test_cpi_Forwarding
+test_cpi_Interface
+test_cpi_InterfaceEthernet
+test_cpi_InterfaceGeneric
+test_cpi_InterfaceIPTunnel
+test_cpi_InterfaceIPTunnelList
+test_cpi_InterfaceSet
+test_cpi_InterfaceTypes
+test_cpi_Listener
+test_cpi_ManageLinks
+test_cpi_NameRouteType
+test_cpi_Registration
+test_cpi_RouteEntry
+test_cpi_RouteEntryList
diff --git a/libccnx-transport-rta/ccnx/api/control/test/CMakeLists.txt b/libccnx-transport-rta/ccnx/api/control/test/CMakeLists.txt
new file mode 100644
index 00000000..a573213c
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/CMakeLists.txt
@@ -0,0 +1,36 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_cpi_Acks
+ test_cpi_Address
+ test_cpi_AddressList
+ test_cpi_CancelFlow
+ test_cpi_Connection
+ test_cpi_ConnectionEthernet
+ test_cpi_ConnectionList
+ test_cpi_ControlMessage
+ test_cpi_ControlFacade
+ test_cpi_Interface
+ test_cpi_InterfaceSet
+ test_cpi_InterfaceTypes
+ test_cpi_InterfaceGeneric
+ test_cpi_InterfaceEthernet
+ test_cpi_InterfaceIPTunnel
+ test_cpi_InterfaceIPTunnelList
+ test_cpi_Forwarding
+ test_cpi_Listener
+ test_cpi_ManageLinks
+ test_cpi_NameRouteType
+ test_cpi_Registration
+ test_cpi_RouteEntry
+ test_cpi_RouteEntryList
+ test_controlPlaneInterface
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_controlPlaneInterface.c b/libccnx-transport-rta/ccnx/api/control/test/test_controlPlaneInterface.c
new file mode 100644
index 00000000..8dfbb362
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_controlPlaneInterface.c
@@ -0,0 +1,287 @@
+/*
+ * 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 "../controlPlaneInterface.c"
+
+#include <LongBow/unit-test.h>
+
+#include <ccnx/api/control/cpi_ControlFacade.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(controlPlaneInterface)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(controlPlaneInterface)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(controlPlaneInterface)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpi_CreateRequest);
+ LONGBOW_RUN_TEST_CASE(Global, cpi_CreateResponse);
+ LONGBOW_RUN_TEST_CASE(Global, cpi_ParseRequest);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpi_PauseInput);
+
+ LONGBOW_RUN_TEST_CASE(Global, controlPlaneInterface_PauseInput);
+}
+
+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, cpi_CreateRequest)
+{
+ const char key_looney[] = "looney";
+
+ PARCJSON *operation = parcJSON_Create();
+ parcJSON_AddString(operation, "bugs", "bunny");
+
+ PARCJSON *request = cpi_CreateRequest(key_looney, operation);
+ parcJSON_Release(&operation);
+
+ PARCJSONValue *value = parcJSON_GetValueByName(request, cpiRequest);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpiRequest,
+ parcJSON_ToString(request));
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Key %s wrong type: %s",
+ cpiRequest,
+ parcJSON_ToString(request));
+ PARCJSON *test_request_key = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(test_request_key, cpiSeqnum);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpiSeqnum,
+ parcJSON_ToString(request));
+ assertTrue(parcJSONValue_IsNumber(value),
+ "Key %s wrong type: %s",
+ cpiSeqnum,
+ parcJSON_ToString(request));
+
+ value = parcJSON_GetValueByName(test_request_key, key_looney);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ key_looney,
+ parcJSON_ToString(request));
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Key %s wrong type: %s",
+ key_looney,
+ parcJSON_ToString(request));
+
+ parcJSON_Release(&request);
+}
+
+LONGBOW_TEST_CASE(Global, cpi_CreateResponse)
+{
+ const char key_looney[] = "looney";
+
+ PARCJSON *requestOperation = parcJSON_Create();
+ parcJSON_AddString(requestOperation, "bugs", "bunny");
+
+ PARCJSON *requestJson = cpi_CreateRequest(key_looney, requestOperation);
+ parcJSON_Release(&requestOperation);
+
+ //
+ // we should now have an object that looks, like
+ // { "CPI_REQUEST": { "SEQUENCE":1, "looney":{"bugs":"bunny"} } }
+ //
+ // The sequence number might not be exactly 1, depending on how the
+ // unit tests are ordered and forked.
+ //
+ char *expectedStr1 = "{\"CPI_REQUEST\":{\"SEQUENCE\":";
+ char *expectedStr2 = ",\"looney\":{\"bugs\":\"bunny\"}}}";
+ char *jsonStr = parcJSON_ToCompactString(requestJson);
+ size_t len = strlen(expectedStr1);
+ assertTrue(strncmp(jsonStr, expectedStr1, len) == 0, "Expect JSON strings to be the same");
+ assertTrue(strncmp(jsonStr + len + 1, expectedStr2, strlen(expectedStr2)) == 0, "Expect JSON strings to be the same");
+ parcMemory_Deallocate(&jsonStr);
+
+ CCNxControl *request = ccnxControl_CreateCPIRequest(requestJson);
+
+ PARCJSON *responseOperation = parcJSON_Create();
+ parcJSON_AddString(responseOperation, "donald", "duck");
+
+ CCNxControl *response = cpi_CreateResponse(request, responseOperation);
+ parcJSON_Release(&responseOperation);
+
+ PARCJSON *responseJson = ccnxControl_GetJson(response);
+ //
+ // we should now have an object that looks, like
+ // { "CPI_RESPONSE": { "SEQUENCE":1, "looney":{"donald":"duck"} } }
+ //
+ // The sequence number might not be exactly 1, depending on how the
+ // unit tests are ordered and forked. It should be the same as the request.
+ //
+ expectedStr1 = "{\"CPI_RESPONSE\":{\"SEQUENCE\":";
+ expectedStr2 = ",\"looney\":{\"donald\":\"duck\"}}}";
+ jsonStr = parcJSON_ToCompactString(responseJson);
+ len = strlen(expectedStr1);
+ assertTrue(strncmp(jsonStr, expectedStr1, len) == 0, "Expect JSON strings to be the same");
+ assertTrue(strncmp(jsonStr + len + 1, expectedStr2, strlen(expectedStr2)) == 0, "Expect JSON strings to be the same");
+ parcMemory_Deallocate(&jsonStr);
+
+ PARCJSONValue *value = parcJSON_GetValueByName(responseJson, cpiResponse);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpiResponse,
+ parcJSON_ToString(responseJson));
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Key %s wrong type: %s",
+ cpiResponse,
+ parcJSON_ToString(responseJson));
+ PARCJSON *test_response_key = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(test_response_key, cpiSeqnum);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ cpiSeqnum,
+ parcJSON_ToString(test_response_key));
+ assertTrue(parcJSONValue_IsNumber(value),
+ "Key %s wrong type: %s",
+ cpiSeqnum,
+ parcJSON_ToString(responseJson));
+
+ value = parcJSON_GetValueByName(test_response_key, key_looney);
+ assertNotNull(value,
+ "JSON key not found %s: %s",
+ key_looney,
+ parcJSON_ToString(responseJson));
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Key %s wrong type: %s",
+ key_looney,
+ parcJSON_ToString(responseJson));
+
+ ccnxControl_Release(&response);
+ ccnxControl_Release(&request);
+
+ parcJSON_Release(&requestJson);
+}
+
+LONGBOW_TEST_CASE(Global, cpi_ParseRequest)
+{
+ char key_looney[] = "looney";
+ const char value_looney[] = "{\"bugs\":\"bunny\"}";
+
+ PARCJSON *operation = parcJSON_Create();
+ parcJSON_AddString(operation, "bugs", "bunny");
+
+ PARCJSON *request = cpi_CreateRequest(key_looney, operation);
+ parcJSON_Release(&operation);
+
+ //
+ // we should now have an object that looks, like
+ // { "CPI_REQUEST": { "SEQUENCE":1, "looney":{"bugs":"bunny"} } }
+ //
+ // The sequence number might not be exactly 1, depending on how the
+ // unit tests are ordered and forked.
+ //
+
+ PARCJSONPair *parsedOpPair = cpi_ParseRequest(request);
+ assertNotNull(parsedOpPair, "Got null parsed json from %s", parcJSON_ToString(request));
+
+ PARCBuffer *key = parcJSONPair_GetName(parsedOpPair);
+ PARCBuffer *test_key = parcBuffer_WrapCString(key_looney);
+ assertTrue(parcBuffer_Equals(key, test_key),
+ "Key name of parsed wrong, expected %s got %s in %s",
+ key_looney,
+ parcBuffer_ToString(key),
+ parcJSONPair_ToString(parsedOpPair));
+ parcBuffer_Release(&test_key);
+
+ operation = parcJSONValue_GetJSON(parcJSONPair_GetValue(parsedOpPair));
+ char *test_looney = parcJSON_ToCompactString(operation);
+ assertTrue(strcmp(value_looney, test_looney) == 0,
+ "Inner values did not match, expected %s got %s in %s",
+ value_looney,
+ test_looney,
+ parcJSONPair_ToString(parsedOpPair));
+ parcMemory_Deallocate((void **) &test_looney);
+
+ parcJSON_Release(&request);
+}
+
+LONGBOW_TEST_CASE(Global, controlPlaneInterface_PauseInput)
+{
+ CCNxControl *message = ccnxControl_CreatePauseInputRequest();
+
+ assertTrue(ccnxControlFacade_IsCPI(message), "Expected ccnxControlMessage_IsCPI to be true");
+
+ PARCJSON *json = ccnxControlFacade_GetJson(message);
+ assertTrue(ccnxControl_IsCPI(message), "Expected a CPI control message");
+ assertTrue(cpi_getCPIOperation2(json) == CPI_PAUSE,
+ "Expected opertaion %d got %d", CPI_PAUSE, cpi_getCPIOperation2(json));
+
+ ccnxControl_Release(&message);
+}
+
+LONGBOW_TEST_CASE(Global, cpi_PauseInput)
+{
+ PARCJSON *pauseRequest = cpi_CreatePauseInputRequest();
+ CCNxControl *request = ccnxControl_CreateCPIRequest(pauseRequest);
+ parcJSON_Release(&pauseRequest);
+
+ assertTrue(ccnxControl_IsCPI(request), "Is not a CPI message!");
+ assertTrue(cpi_GetMessageType(request) == CPI_REQUEST,
+ "Got wrong message type, expected %d got %d",
+ CPI_REQUEST,
+ cpi_GetMessageType(request));
+
+ assertTrue(cpi_GetMessageOperation(request) == CPI_PAUSE,
+ "got wrong operation, expected %d got %d",
+ CPI_PAUSE,
+ cpi_GetMessageOperation(request));
+
+ ccnxControl_Release(&request);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(controlPlaneInterface);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Acks.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Acks.c
new file mode 100644
index 00000000..ecdcf40f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Acks.c
@@ -0,0 +1,119 @@
+/*
+ * 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 "../cpi_Acks.c"
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+
+LONGBOW_TEST_RUNNER(cpi_Acks)
+{
+ // 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(cpi_Acks)
+{
+ 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(cpi_Acks)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiAck_CreateAck);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAck_CreateNack);
+}
+
+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, cpiAck_CreateAck)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(name);
+ PARCJSON *request = cpiForwarding_CreateAddRouteRequest(route);
+
+ PARCJSON *actual = cpiAcks_CreateAck(request);
+
+ assertTrue(cpiAcks_IsAck(actual), "Expected cpiAcks_IsAck to return true.");
+
+ parcJSON_Release(&actual);
+ parcJSON_Release(&request);
+ cpiRouteEntry_Destroy(&route);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAck_CreateNack)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(name);
+ PARCJSON *request = cpiForwarding_CreateAddRouteRequest(route);
+
+ PARCJSON *actual = cpiAcks_CreateNack(request);
+
+ assertFalse(cpiAcks_IsAck(actual), "Expected cpiAcks_IsAck to return false.");
+
+ parcJSON_Release(&actual);
+ parcJSON_Release(&request);
+ cpiRouteEntry_Destroy(&route);
+ ccnxName_Release(&name);
+}
+
+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(cpi_Acks);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Address.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Address.c
new file mode 100644
index 00000000..fbb63f7d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Address.c
@@ -0,0 +1,550 @@
+/*
+ * 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.
+ */
+
+/**
+ * Each type test (inet, inet6, etc.) should test:
+ * - CreateFromX
+ * - GetX
+ * - GetType = X
+ * - Y = cpiAddress_CreateFromJson( cpiAddress_ToJson(X) ) == X
+ * - Equals(Y, X)
+ * - Equals(Copy(X), X)
+ */
+
+// for inet_pton
+#include <config.h>
+#include <arpa/inet.h>
+#include <LongBow/unit-test.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 "../cpi_Address.c"
+
+LONGBOW_TEST_RUNNER(cpi_Address)
+{
+ // 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(cpi_Address)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(cpi_Address)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_Equals_ReallyEqual);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_Equals_SamePointer);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_Equals_NotEqual);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_CreateFromInet);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_CreateFromInet6);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_CreateFromInterface);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_CreateFromLink);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_CreateFromUnix);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_ToString_INET);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_ToString_INET6);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_ToString_LINK);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_ToString_IFACE);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_ToString_UNIX);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddress_BuildString);
+}
+
+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, cpiAddress_Copy)
+{
+ CPIAddress *a = cpiAddress_CreateFromInterface(1);
+ CPIAddress *b = cpiAddress_Copy(a);
+
+ assertTrue(cpiAddress_Equals(a, b), "Copy did not compare as equal: %s and %s", cpiAddress_ToString(a), cpiAddress_ToString(b));
+
+ cpiAddress_Destroy(&a);
+ cpiAddress_Destroy(&b);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddress_Equals_ReallyEqual)
+{
+ struct sockaddr_in addr_in;
+ memset(&addr_in, 0, sizeof(struct sockaddr_in));
+
+ addr_in.sin_addr.s_addr = 0x01020304;
+ addr_in.sin_family = AF_INET;
+ addr_in.sin_port = 0x0A0B;
+
+ CPIAddress *a = cpiAddress_CreateFromInet(&addr_in);
+ CPIAddress *b = cpiAddress_CreateFromInet(&addr_in);
+
+ assertTrue(cpiAddress_Equals(a, b), "Equals did not compare two equal addresses: %s and %s", cpiAddress_ToString(a), cpiAddress_ToString(b));
+
+ cpiAddress_Destroy(&a);
+ cpiAddress_Destroy(&b);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddress_Equals_SamePointer)
+{
+ struct sockaddr_in addr_in;
+ memset(&addr_in, 0, sizeof(struct sockaddr_in));
+
+ addr_in.sin_addr.s_addr = 0x01020304;
+ addr_in.sin_family = AF_INET;
+ addr_in.sin_port = 0x0A0B;
+
+ CPIAddress *a = cpiAddress_CreateFromInet(&addr_in);
+
+ assertTrue(cpiAddress_Equals(a, a), "Equals did not compare two equal addresses: %s and %s", cpiAddress_ToString(a), cpiAddress_ToString(a));
+
+ cpiAddress_Destroy(&a);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddress_Equals_NotEqual)
+{
+ struct sockaddr_in addr_in;
+ memset(&addr_in, 0, sizeof(struct sockaddr_in));
+
+ addr_in.sin_addr.s_addr = 0x01020304;
+ addr_in.sin_family = AF_INET;
+ addr_in.sin_port = 0x0A0B;
+
+ CPIAddress *a = cpiAddress_CreateFromInet(&addr_in);
+ CPIAddress *b = cpiAddress_CreateFromInterface(1);
+
+ assertFalse(cpiAddress_Equals(a, b), "Equals failed on different addresses: %s and %s", cpiAddress_ToString(a), cpiAddress_ToString(b));
+
+ cpiAddress_Destroy(&a);
+ cpiAddress_Destroy(&b);
+}
+
+
+LONGBOW_TEST_CASE(Global, cpiAddress_CreateFromInet)
+{
+ struct sockaddr_in addr_in;
+ struct sockaddr_in addr_test;
+ memset(&addr_in, 0, sizeof(struct sockaddr_in));
+
+ addr_in.sin_addr.s_addr = 0x01020304;
+ addr_in.sin_family = AF_INET;
+ addr_in.sin_port = 0x0A0B;
+
+ CPIAddress *address = cpiAddress_CreateFromInet(&addr_in);
+
+ bool success = cpiAddress_GetInet(address, &addr_test);
+ assertTrue(success, "Got false converting back address");
+
+ assertTrue(memcmp(&addr_in, &addr_test, sizeof(struct sockaddr_in)) == 0, "Got mismatch addressed");
+
+ assertTrue(cpiAddress_GetType(address) == cpiAddressType_INET,
+ "Got wrong address type, expected %d, got %d", cpiAddressType_INET, cpiAddress_GetType(address));
+
+ PARCJSON *json = cpiAddress_ToJson(address);
+ CPIAddress *fromjson = cpiAddress_CreateFromJson(json);
+
+ assertTrue(cpiAddress_GetType(address) == cpiAddress_GetType(fromjson), "fromjson type does not equal known");
+ assertTrue(parcBuffer_Equals(address->blob, fromjson->blob), "fromjson blob does not equal known address");
+ assertTrue(cpiAddress_Equals(address, fromjson), "cpiAddress_Equals broken for INET type");
+
+ // This test does too much. Case 1032
+ CPIAddress *copy = cpiAddress_Copy(address);
+ assertTrue(cpiAddress_Equals(copy, address), "Copy and address not equal for INET");
+
+ cpiAddress_Destroy(&copy);
+ cpiAddress_Destroy(&fromjson);
+
+ parcJSON_Release(&json);
+
+ cpiAddress_Destroy(&address);
+ return;
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddress_CreateFromInet6)
+{
+ struct sockaddr_in6 addr_in6;
+ memset(&addr_in6, 0, sizeof(struct sockaddr_in6));
+
+ inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr));
+ addr_in6.sin6_family = AF_INET6;
+ addr_in6.sin6_port = 0x0A0B;
+ addr_in6.sin6_flowinfo = 0x01020304;
+
+ CPIAddress *address = cpiAddress_CreateFromInet6(&addr_in6);
+
+ struct sockaddr_in6 addr_test;
+ bool success = cpiAddress_GetInet6(address, &addr_test);
+ assertTrue(success, "Got false converting back address");
+
+ assertTrue(memcmp(&addr_in6, &addr_test, sizeof(struct sockaddr_in6)) == 0, "Got mismatch addressed");
+
+ assertTrue(cpiAddress_GetType(address) == cpiAddressType_INET6,
+ "Got wrong address type, expected %d, got %d", cpiAddressType_INET6, cpiAddress_GetType(address));
+
+ PARCJSON *json = cpiAddress_ToJson(address);
+ CPIAddress *fromjson = cpiAddress_CreateFromJson(json);
+
+ assertTrue(parcBuffer_Equals(address->blob, fromjson->blob), "fromjson blob does not equal known address");
+ assertTrue(cpiAddress_Equals(address, fromjson), "cpiAddress_Equals broken for INET6 type");
+
+ CPIAddress *copy = cpiAddress_Copy(address);
+ assertTrue(cpiAddress_Equals(copy, address), "Copy and address not equal for INET6");
+
+ parcJSON_Release(&json);
+ cpiAddress_Destroy(&address);
+ cpiAddress_Destroy(&copy);
+ cpiAddress_Destroy(&fromjson);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddress_CreateFromUnix)
+{
+ struct sockaddr_un addr_un;
+ struct sockaddr_un addr_test;
+ memset(&addr_un, 0, sizeof(struct sockaddr_un));
+ char path[] = "/Hello/Cruel/World";
+ strcpy(addr_un.sun_path, path);
+ addr_un.sun_family = AF_UNIX;
+
+ CPIAddress *address = cpiAddress_CreateFromUnix(&addr_un);
+
+ bool success = cpiAddress_GetUnix(address, &addr_test);
+ assertTrue(success, "Got false converting back address");
+
+ assertTrue(memcmp(&addr_un, &addr_test, sizeof(struct sockaddr_un)) == 0, "Got mismatch addressed");
+
+ assertTrue(cpiAddress_GetType(address) == cpiAddressType_UNIX,
+ "Got wrong address type, expected %d, got %d", cpiAddressType_UNIX, cpiAddress_GetType(address));
+
+ PARCJSON *json = cpiAddress_ToJson(address);
+ CPIAddress *fromjson = cpiAddress_CreateFromJson(json);
+
+ assertTrue(parcBuffer_Equals(address->blob, fromjson->blob), "fromjson blob does not equal known address");
+ assertTrue(cpiAddress_Equals(address, fromjson), "cpiAddress_Equals broken for UNIX type");
+
+ CPIAddress *copy = cpiAddress_Copy(address);
+ assertTrue(cpiAddress_Equals(copy, address), "Copy and address not equal for UNIX");
+
+ parcJSON_Release(&json);
+ cpiAddress_Destroy(&address);
+ cpiAddress_Destroy(&copy);
+ cpiAddress_Destroy(&fromjson);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddress_CreateFromInterface)
+{
+ uint32_t ifidx = 0x01020304;
+ uint32_t test;
+
+ CPIAddress *address = cpiAddress_CreateFromInterface(ifidx);
+
+ bool success = cpiAddress_GetInterfaceIndex(address, &test);
+ assertTrue(success, "Got false converting back address");
+
+ assertTrue(ifidx == test, "Got mismatch addressed");
+
+ assertTrue(cpiAddress_GetType(address) == cpiAddressType_IFACE,
+ "Got wrong address type, expected %d, got %d", cpiAddressType_IFACE, cpiAddress_GetType(address));
+
+ PARCJSON *json = cpiAddress_ToJson(address);
+ CPIAddress *fromjson = cpiAddress_CreateFromJson(json);
+
+ assertTrue(parcBuffer_Equals(address->blob, fromjson->blob), "fromjson blob does not equal known address");
+ assertTrue(cpiAddress_Equals(address, fromjson), "cpiAddress_Equals broken for IFACE type");
+
+ CPIAddress *copy = cpiAddress_Copy(address);
+ assertTrue(cpiAddress_Equals(copy, address), "Copy and address not equal for IFACE");
+
+ parcJSON_Release(&json);
+ cpiAddress_Destroy(&address);
+ cpiAddress_Destroy(&copy);
+ cpiAddress_Destroy(&fromjson);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddress_CreateFromLink)
+{
+ uint8_t mac[] = { 0x01, 0x02, 0x03, 0x04, 0xFF, 0x8F };
+ PARCBuffer *macbuffer = parcBuffer_Flip(parcBuffer_CreateFromArray(mac, sizeof(mac)));
+
+ CPIAddress *address = cpiAddress_CreateFromLink(mac, sizeof(mac));
+
+ // Do not release test, it is the same reference as address->blob
+ PARCBuffer *test = cpiAddress_GetLinkAddress(address);
+ assertNotNull(test, "Got null link address buffer");
+ assertTrue(parcBuffer_Equals(test, address->blob), "Returned buffer from cpiAddress_GetLinkAddress not equal to address");
+
+ assertTrue(cpiAddress_GetType(address) == cpiAddressType_LINK,
+ "Got wrong address type, expected %d, got %d", cpiAddressType_LINK, cpiAddress_GetType(address));
+
+ PARCJSON *json = cpiAddress_ToJson(address);
+ CPIAddress *fromjson = cpiAddress_CreateFromJson(json);
+
+ assertTrue(cpiAddress_GetType(address) == cpiAddress_GetType(fromjson),
+ "fromjson type does not equal known");
+ assertTrue(parcBuffer_Equals(address->blob, fromjson->blob),
+ "fromjson blob does not equal known address");
+ assertTrue(cpiAddress_Equals(address, fromjson),
+ "cpiAddress_Equals broken for LINK type");
+
+ CPIAddress *copy = cpiAddress_Copy(address);
+ assertTrue(cpiAddress_Equals(copy, address),
+ "Copy and address not equal for LINK");
+
+ parcJSON_Release(&json);
+ cpiAddress_Destroy(&address);
+ cpiAddress_Destroy(&copy);
+ cpiAddress_Destroy(&fromjson);
+ parcBuffer_Release(&macbuffer);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddress_ToString_INET)
+{
+ struct sockaddr_in *addr_in = parcNetwork_SockInet4Address("1.2.3.4", 12345);
+
+ char expected[] = "inet4://1.2.3.4:12345";
+
+ CPIAddress *cpiaddr = cpiAddress_CreateFromInet(addr_in);
+
+ char *actual = cpiAddress_ToString(cpiaddr);
+
+ assertTrue(strcmp(actual, expected) == 0, "Bad string, expected '%s' got '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ cpiAddress_Destroy(&cpiaddr);
+ parcMemory_Deallocate((void **) &addr_in);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddress_ToString_UNIX)
+{
+ struct sockaddr_un addr_un;
+ char path[] = "/Hello/Cruel/World";
+ memset(&addr_un, 0, sizeof(struct sockaddr_un));
+ strcpy(addr_un.sun_path, path);
+ addr_un.sun_family = AF_UNIX;
+
+ char truth_str[] = "{ .type=UNIX, .data={ .path=/Hello/Cruel/World, .len=18 } }";
+
+ CPIAddress *cpiaddr = cpiAddress_CreateFromUnix(&addr_un);
+
+ char *output = cpiAddress_ToString(cpiaddr);
+
+ assertTrue(strcmp(output, truth_str) == 0, "Bad string, expected %s got %s", truth_str, output);
+
+ parcMemory_Deallocate((void **) &output);
+ cpiAddress_Destroy(&cpiaddr);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddress_ToString_INET6)
+{
+ struct sockaddr_in6 addr_in6;
+ memset(&addr_in6, 0, sizeof(struct sockaddr_in6));
+
+ inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr));
+ addr_in6.sin6_family = AF_INET6;
+ addr_in6.sin6_port = htons(43215);
+
+ char *expected = "inet6://[2001:720:1500:1::a100%0]:43215";
+
+ CPIAddress *cpiaddr = cpiAddress_CreateFromInet6(&addr_in6);
+ char *actual = cpiAddress_ToString(cpiaddr);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ cpiAddress_Destroy(&cpiaddr);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddress_ToString_LINK)
+{
+ uint8_t addr[6] = { 0x01, 0x02, 0x03, 0xF4, 0xF5, 0xF6 };
+
+ char truth_str[] = "link://01-02-03-f4-f5-f6";
+
+ CPIAddress *cpiaddr = cpiAddress_CreateFromLink(addr, sizeof(addr));
+ char *output = cpiAddress_ToString(cpiaddr);
+
+ assertTrue(strcmp(output, truth_str) == 0,
+ "Bad string, expected %s got %s", truth_str, output);
+
+ parcMemory_Deallocate((void **) &output);
+ cpiAddress_Destroy(&cpiaddr);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddress_ToString_IFACE)
+{
+ char truth_str[] = "{ .type=IFACE, .data={ .ifidx=55 } }";
+
+ CPIAddress *cpiaddr = cpiAddress_CreateFromInterface(55);
+ char *output = cpiAddress_ToString(cpiaddr);
+
+ assertTrue(strcmp(output, truth_str) == 0, "Bad string, expected %s got %s", truth_str, output);
+
+ parcMemory_Deallocate((void **) &output);
+ cpiAddress_Destroy(&cpiaddr);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddress_BuildString)
+{
+ CPIAddress *address = cpiAddress_CreateFromInterface(1);
+ uint32_t beforeBalance = parcMemory_Outstanding();
+ PARCBufferComposer *composer = cpiAddress_BuildString(address, parcBufferComposer_Create());
+ parcBufferComposer_Release(&composer);
+ uint32_t afterBalance = parcMemory_Outstanding();
+
+ cpiAddress_Destroy(&address);
+ assertTrue(beforeBalance == afterBalance, "Memory leak off by %d allocations", (int) (afterBalance - beforeBalance));
+}
+
+// ===============================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _Inet_BuildString);
+ LONGBOW_RUN_TEST_CASE(Local, _Inet6_BuildString);
+ LONGBOW_RUN_TEST_CASE(Local, _LinkToString);
+ LONGBOW_RUN_TEST_CASE(Local, _IfaceToString);
+}
+
+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, _Inet_BuildString)
+{
+ struct sockaddr_in addr_in;
+ addr_in.sin_addr.s_addr = 0x04030201;
+ addr_in.sin_port = htons(12345);
+
+ char *expected = "inet4://1.2.3.4:12345";
+
+ CPIAddress *cpiaddr = cpiAddress_CreateFromInet(&addr_in);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ _Inet_BuildString(cpiaddr, composer);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ cpiAddress_Destroy(&cpiaddr);
+}
+
+LONGBOW_TEST_CASE(Local, _Inet6_BuildString)
+{
+ struct sockaddr_in6 addr_in6;
+ memset(&addr_in6, 0, sizeof(struct sockaddr_in6));
+
+ inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr));
+ addr_in6.sin6_family = AF_INET6;
+ addr_in6.sin6_port = htons(43215);
+
+ char *expected = "inet6://[2001:720:1500:1::a100%0]:43215";
+
+ CPIAddress *cpiaddr = cpiAddress_CreateFromInet6(&addr_in6);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ _Inet6_BuildString(cpiaddr, composer);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ cpiAddress_Destroy(&cpiaddr);
+}
+
+LONGBOW_TEST_CASE(Local, _LinkToString)
+{
+ uint8_t addr[6] = { 0x01, 0x02, 0x03, 0xF4, 0xF5, 0xF6 };
+
+ char *expected = "link://01-02-03-f4-f5-f6";
+
+ CPIAddress *cpiaddr = cpiAddress_CreateFromLink(addr, sizeof(addr));
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ _Link_BuildString(cpiaddr, composer);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ cpiAddress_Destroy(&cpiaddr);
+}
+
+LONGBOW_TEST_CASE(Local, _IfaceToString)
+{
+ char truth_str[] = "{ .ifidx=55 }";
+
+ CPIAddress *cpiaddr = cpiAddress_CreateFromInterface(55);
+
+ char output[1024];
+ ssize_t output_length = _IfaceToString(output, 1024, cpiaddr->blob);
+ assertTrue(strcmp(output, truth_str) == 0, "Bad string, expected %s got %s", truth_str, output);
+ assertTrue(strlen(truth_str) == output_length, "Got wrong output size, expected %zd got %zd", strlen(truth_str), output_length);
+
+ cpiAddress_Destroy(&cpiaddr);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_Address);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_AddressList.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_AddressList.c
new file mode 100644
index 00000000..f4887a45
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_AddressList.c
@@ -0,0 +1,317 @@
+/*
+ * 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 "../cpi_AddressList.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+
+LONGBOW_TEST_RUNNER(cpi_AddressList)
+{
+ // 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(cpi_AddressList)
+{
+ 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(cpi_AddressList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Append);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_GetItem);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Equals_same_pointer);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Equals_both_empty);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Equals_unequal_sizes);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Equals_same_lists);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Equals_wrong_order);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_FromJSON);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_ToFromJSON);
+ LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_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, cpiAddressList_Append)
+{
+ CPIAddressList *list = cpiAddressList_Create();
+ unsigned loops = 10;
+
+ for (unsigned i = 0; i < loops; i++) {
+ cpiAddressList_Append(list, cpiAddress_CreateFromInterface(i));
+ }
+
+ assertTrue(cpiAddressList_Length(list) == loops,
+ "Got wrong length, expected %u got %zu",
+ loops,
+ cpiAddressList_Length(list));
+
+ cpiAddressList_Destroy(&list);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddressList_Copy)
+{
+ CPIAddressList *list = cpiAddressList_Create();
+ unsigned loops = 10;
+
+ for (unsigned i = 0; i < loops; i++) {
+ cpiAddressList_Append(list, cpiAddress_CreateFromInterface(i));
+ }
+
+ CPIAddressList *copy = cpiAddressList_Copy(list);
+ assertTrue(cpiAddressList_Length(copy) == cpiAddressList_Length(list),
+ "Copy wrong size, got %zu expected %zu",
+ cpiAddressList_Length(copy),
+ cpiAddressList_Length(list));
+
+ for (unsigned i = 0; i < cpiAddressList_Length(copy); i++) {
+ const CPIAddress *truth = cpiAddressList_GetItem(list, i);
+ const CPIAddress *test = cpiAddressList_GetItem(copy, i);
+ assertTrue(cpiAddress_Equals(truth, test), "Lists do not match at element %u", i);
+ }
+
+ cpiAddressList_Destroy(&list);
+ cpiAddressList_Destroy(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddressList_Create_Destroy)
+{
+ CPIAddressList *list = cpiAddressList_Create();
+ cpiAddressList_Destroy(&list);
+ assertTrue(parcMemory_Outstanding() == 0, "Got memory imbalance: %u", parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddressList_GetItem)
+{
+ CPIAddressList *list = cpiAddressList_Create();
+ unsigned loops = 10;
+
+ for (unsigned i = 0; i < loops; i++) {
+ cpiAddressList_Append(list, cpiAddress_CreateFromInterface(i));
+ }
+
+ assertTrue(cpiAddressList_Length(list) == loops,
+ "Got wrong length, expected %u got %zu",
+ loops,
+ cpiAddressList_Length(list));
+
+ CPIAddress *truth = cpiAddress_CreateFromInterface(5);
+ const CPIAddress *test = cpiAddressList_GetItem(list, 5);
+ assertTrue(cpiAddress_Equals(truth, test), "Item 5 did not match!");
+
+ cpiAddressList_Destroy(&list);
+ cpiAddress_Destroy(&truth);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddressList_Equals_same_pointer)
+{
+ CPIAddressList *list = cpiAddressList_Create();
+ assertTrue(cpiAddressList_Equals(list, list), "list != list, that's wrong");
+ cpiAddressList_Destroy(&list);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddressList_Equals_both_empty)
+{
+ CPIAddressList *a = cpiAddressList_Create();
+ CPIAddressList *b = cpiAddressList_Create();
+ assertTrue(cpiAddressList_Equals(a, b), "emtpy list != empty list, that's wrong");
+ cpiAddressList_Destroy(&a);
+ cpiAddressList_Destroy(&b);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddressList_Equals_unequal_sizes)
+{
+ CPIAddressList *a = cpiAddressList_Create();
+ CPIAddressList *b = cpiAddressList_Create();
+ cpiAddressList_Append(a, cpiAddress_CreateFromInterface(1));
+ assertFalse(cpiAddressList_Equals(a, b), "length 0 == length 1, that's wrong");
+ cpiAddressList_Destroy(&a);
+ cpiAddressList_Destroy(&b);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddressList_Equals_same_lists)
+{
+ CPIAddressList *a = cpiAddressList_Create();
+ CPIAddressList *b = cpiAddressList_Create();
+ cpiAddressList_Append(a, cpiAddress_CreateFromInterface(1));
+ cpiAddressList_Append(a, cpiAddress_CreateFromInterface(2));
+ cpiAddressList_Append(b, cpiAddress_CreateFromInterface(1));
+ cpiAddressList_Append(b, cpiAddress_CreateFromInterface(2));
+ assertTrue(cpiAddressList_Equals(a, b), "same lists not equal, that's wrong");
+ cpiAddressList_Destroy(&a);
+ cpiAddressList_Destroy(&b);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddressList_Equals_wrong_order)
+{
+ CPIAddressList *a = cpiAddressList_Create();
+ CPIAddressList *b = cpiAddressList_Create();
+ cpiAddressList_Append(a, cpiAddress_CreateFromInterface(1));
+ cpiAddressList_Append(a, cpiAddress_CreateFromInterface(2));
+ cpiAddressList_Append(b, cpiAddress_CreateFromInterface(2));
+ cpiAddressList_Append(b, cpiAddress_CreateFromInterface(1));
+ assertFalse(cpiAddressList_Equals(a, b), "out of order lists equal, that's wrong");
+ cpiAddressList_Destroy(&a);
+ cpiAddressList_Destroy(&b);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddressList_ToJSON)
+{
+ char truth[] = "[{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAA==\"},{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAQ==\"}]";
+
+ CPIAddressList *a = cpiAddressList_Create();
+ int loops = 2;
+ for (int i = 0; i < loops; i++) {
+ cpiAddressList_Append(a, cpiAddress_CreateFromInterface(i));
+ }
+
+ PARCJSONArray *jsonArray = cpiAddressList_ToJson(a);
+ char *test = parcJSONArray_ToCompactString(jsonArray);
+
+ assertTrue(strcmp(truth, test) == 0, "JSON strings did not match, got '%s' expected '%s'", test, truth);
+
+ cpiAddressList_Destroy(&a);
+ parcMemory_Deallocate((void **) &test);
+ parcJSONArray_Release(&jsonArray);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddressList_FromJSON)
+{
+ char json_str[] = "{\"ARRAY\":[{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAA==\"},{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAQ==\"}]}";
+ PARCJSON *json = parcJSON_ParseString(json_str);
+
+ PARCJSONArray *jsonArray = parcJSONValue_GetArray(parcJSON_GetValueByIndex(json, 0));
+
+ CPIAddressList *test_list = cpiAddressList_CreateFromJson(jsonArray);
+
+ CPIAddressList *truth_list = cpiAddressList_Create();
+ int loops = 2;
+ for (int i = 0; i < loops; i++) {
+ cpiAddressList_Append(truth_list, cpiAddress_CreateFromInterface(i));
+ }
+
+ assertTrue(cpiAddressList_Equals(truth_list, test_list), "Lists did not match!");
+
+ cpiAddressList_Destroy(&truth_list);
+ cpiAddressList_Destroy(&test_list);
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddressList_ToFromJSON)
+{
+ CPIAddressList *truth_list = cpiAddressList_Create();
+ int loops = 2;
+ for (int i = 0; i < loops; i++) {
+ cpiAddressList_Append(truth_list, cpiAddress_CreateFromInterface(i));
+ }
+
+ PARCJSONArray *json = cpiAddressList_ToJson(truth_list);
+
+ CPIAddressList *test_list = cpiAddressList_CreateFromJson(json);
+
+ assertTrue(cpiAddressList_Equals(truth_list, test_list), "Lists did not match!");
+
+ cpiAddressList_Destroy(&truth_list);
+ cpiAddressList_Destroy(&test_list);
+ parcJSONArray_Release(&json);
+}
+
+LONGBOW_TEST_CASE(Global, cpiAddressList_ToString)
+{
+ CPIAddressList *truth_list = cpiAddressList_Create();
+ int loops = 2;
+ for (int i = 0; i < loops; i++) {
+ cpiAddressList_Append(truth_list, cpiAddress_CreateFromInterface(i));
+ }
+
+ uint32_t beforeMemory = parcMemory_Outstanding();
+ char *string = cpiAddressList_ToString(truth_list);
+ assertNotNull(string, "Got null string from ToString");
+ parcMemory_Deallocate((void **) &string);
+ uint32_t afterMemory = parcMemory_Outstanding();
+
+ cpiAddressList_Destroy(&truth_list);
+
+ assertTrue(beforeMemory == afterMemory, "Memory leak from ToString by %d allocations", (int) (afterMemory - beforeMemory));
+}
+
+// ========================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _cpiAddressList_FreeAddress);
+}
+
+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, _cpiAddressList_FreeAddress)
+{
+ CPIAddress *address = cpiAddress_CreateFromInterface(1);
+ _cpiAddressList_FreeAddress((void **) &address);
+
+ assertTrue(parcMemory_Outstanding() == 0, "Got memory imbalance: %u", parcMemory_Outstanding());
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_AddressList);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_CancelFlow.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_CancelFlow.c
new file mode 100644
index 00000000..8bdc4e17
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_CancelFlow.c
@@ -0,0 +1,115 @@
+/*
+ * 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 "../cpi_CancelFlow.c"
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <inttypes.h>
+
+
+
+LONGBOW_TEST_RUNNER(cpi_CancelFlow)
+{
+ // 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(cpi_CancelFlow)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(cpi_CancelFlow)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiCancelFlow_CreateRequest);
+ LONGBOW_RUN_TEST_CASE(Global, cpiCancelFlow_NameFromControlMessage);
+}
+
+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, cpiCancelFlow_CreateRequest)
+{
+ const char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"CPI_CANCEL_FLOW\":{\"FLOW_NAME\":\"ccnx:/who/doesnt/like/pie\"}}}";
+
+ CCNxName *name = ccnxName_CreateFromCString("lci:/who/doesnt/like/pie");
+ PARCJSON *cpiRequest = cpiCancelFlow_CreateRequest(name);
+ CCNxControl *controlRequest = ccnxControl_CreateCPIRequest(cpiRequest);
+
+ PARCJSON *json = ccnxControl_GetJson(controlRequest);
+
+ char buffer[1024];
+ sprintf(buffer, truth_format, cpi_GetSequenceNumber(controlRequest));
+
+ char *test_string = parcJSON_ToCompactString(json);
+ assertTrue(strcmp(buffer, test_string) == 0, "Incorrect JSON, expected '%s' got '%s'", buffer, test_string);
+ parcMemory_Deallocate((void **) &test_string);
+
+ ccnxControl_Release(&controlRequest);
+ parcJSON_Release(&cpiRequest);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, cpiCancelFlow_NameFromControlMessage)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/who/doesnt/like/pie");
+ PARCJSON *cpiRequest = cpiCancelFlow_CreateRequest(name);
+ CCNxControl *controlRequest = ccnxControl_CreateCPIRequest(cpiRequest);
+
+ CCNxName *test_name = cpiCancelFlow_NameFromControlMessage(controlRequest);
+ assertTrue(ccnxName_Equals(test_name, name),
+ "Expected %s actual %s",
+ ccnxName_ToString(name),
+ ccnxName_ToString(test_name));
+
+ ccnxName_Release(&test_name);
+ ccnxControl_Release(&controlRequest);
+ parcJSON_Release(&cpiRequest);
+ ccnxName_Release(&name);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_CancelFlow);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Connection.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Connection.c
new file mode 100644
index 00000000..3656611f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Connection.c
@@ -0,0 +1,220 @@
+/*
+ * 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 "../cpi_Connection.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+
+LONGBOW_TEST_RUNNER(cpi_Connection)
+{
+ // 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(cpi_Connection)
+{
+ 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(cpi_Connection)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnection_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnection_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnection_GetAddresses);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnection_GetIndex);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnection_GetState);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnection_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnection_FromJSON);
+}
+
+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, cpiConnection_Copy)
+{
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIConnection *iptun = cpiConnection_Create(1, src, dst, cpiConnection_TCP);
+
+ CPIConnection *copy = cpiConnection_Copy(iptun);
+
+ assertTrue(cpiConnection_GetIndex(copy) == cpiConnection_GetIndex(iptun),
+ "ifidx did not match, expected %u got %u",
+ cpiConnection_GetIndex(iptun),
+ cpiConnection_GetIndex(copy));
+
+ assertTrue(cpiConnection_GetState(copy) == cpiConnection_GetState(iptun),
+ "states did not match, expected %d got %d",
+ cpiConnection_GetState(iptun),
+ cpiConnection_GetState(copy));
+
+ assertTrue(cpiAddress_Equals(cpiConnection_GetSourceAddress(copy), cpiConnection_GetSourceAddress(iptun)),
+ "did not get same source address");
+ assertTrue(cpiAddress_Equals(cpiConnection_GetDestinationAddress(copy), cpiConnection_GetDestinationAddress(iptun)),
+ "did not get same destination address");
+
+ assertTrue(cpiConnection_GetConnectionType(copy) == cpiConnection_GetConnectionType(iptun),
+ "did not get same connection types!");
+
+ cpiConnection_Release(&copy);
+ cpiConnection_Release(&iptun);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnection_Create_Destroy)
+{
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIConnection *iptun = cpiConnection_Create(1, src, dst, cpiConnection_GRE);
+ cpiConnection_Release(&iptun);
+
+ assertTrue(parcMemory_Outstanding() == 0, "Imbalance after destroying");
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnection_GetAddresses)
+{
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIConnection *iptun = cpiConnection_Create(1, src, dst, cpiConnection_TCP);
+
+ const CPIAddress *test;
+
+ test = cpiConnection_GetSourceAddress(iptun);
+ assertTrue(cpiAddress_Equals(src, test), "Address lists did not match");
+
+ test = cpiConnection_GetDestinationAddress(iptun);
+ assertTrue(cpiAddress_Equals(dst, test), "Address lists did not match");
+
+ cpiConnection_Release(&iptun);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnection_GetIndex)
+{
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIConnection *iptun = cpiConnection_Create(1, src, dst, cpiConnection_TCP);
+
+ assertTrue(cpiConnection_GetIndex(iptun) == 1, "ifidx did not match");
+
+ cpiConnection_Release(&iptun);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnection_GetState)
+{
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIConnection *iptun = cpiConnection_Create(1, src, dst, cpiConnection_TCP);
+
+ assertTrue(cpiConnection_GetState(iptun) == CPI_IFACE_UNKNOWN, "state did not match");
+
+ cpiConnection_SetState(iptun, CPI_IFACE_UP);
+ assertTrue(cpiConnection_GetState(iptun) == CPI_IFACE_UP, "state did not match");
+
+ cpiConnection_SetState(iptun, CPI_IFACE_DOWN);
+ assertTrue(cpiConnection_GetState(iptun) == CPI_IFACE_DOWN, "state did not match");
+
+ cpiConnection_Release(&iptun);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnection_ToJSON)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform.
+#if defined(__APPLE__)
+ char *expected = "{\"Connection\":{\"IFIDX\":1,\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAgHBgUAAAAAAAAAAA==\"}}}";
+#elif defined(__linux__)
+ char *expected = "{\"Connection\":{\"IFIDX\":1,\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAgHBgUAAAAAAAAAAA==\"}}}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIConnection *iptun = cpiConnection_Create(1, src, dst, cpiConnection_TCP);
+
+ PARCJSON *test_json = cpiConnection_ToJson(iptun);
+
+ char *actual = parcJSON_ToCompactString(test_json);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSON_Release(&test_json);
+ cpiConnection_Release(&iptun);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnection_FromJSON)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform.
+#if defined(__APPLE__)
+ char *input = "{\"Connection\":{\"IFIDX\":1,\"STATE\":\"UP\",\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAgHBgUAAAAAAAAAAA==\"}}}";
+#elif defined(__linux__)
+ char *input = "{\"Connection\":{\"IFIDX\":1,\"STATE\":\"UP\",\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAgHBgUAAAAAAAAAAA==\"}}}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIConnection *expected = cpiConnection_Create(1, src, dst, cpiConnection_TCP);
+ cpiConnection_SetState(expected, CPI_IFACE_UP);
+
+ PARCJSON *json = parcJSON_ParseString(input);
+
+ CPIConnection *actual = cpiConnection_CreateFromJson(json);
+ assertTrue(cpiConnection_Equals(expected, actual), "Connection interfaces do not match");
+
+ parcJSON_Release(&json);
+ cpiConnection_Release(&expected);
+ cpiConnection_Release(&actual);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_Connection);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionEthernet.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionEthernet.c
new file mode 100644
index 00000000..4646eccf
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionEthernet.c
@@ -0,0 +1,290 @@
+/*
+ * 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 "../cpi_ConnectionEthernet.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+
+typedef struct test_data {
+ CPIConnectionEthernet *etherConn;
+
+ // the truth values of the connection
+ uint8_t macArray[6];
+ CPIAddress *macAddress;
+ uint16_t ethertype;
+ char ifname[16];
+ char symbolic[16];
+} TestData;
+
+static CPIConnectionEthernet *
+conjureObject(uint8_t mac[6], uint16_t ethertype, const char *ifname, const char *symbolic)
+{
+ CPIAddress *macAddress = cpiAddress_CreateFromLink(mac, 6);
+ CPIConnectionEthernet *etherConn = cpiConnectionEthernet_Create(ifname, macAddress, ethertype, symbolic);
+ cpiAddress_Destroy(&macAddress);
+ return etherConn;
+}
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ uint8_t mac[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ memcpy(data->macArray, mac, 6);
+ data->macAddress = cpiAddress_CreateFromLink(data->macArray, 6);
+ data->ethertype = 0x0801;
+ sprintf(data->ifname, "em1");
+ sprintf(data->symbolic, "conn0");
+
+ data->etherConn = cpiConnectionEthernet_Create(data->ifname, data->macAddress, data->ethertype, data->symbolic);
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ cpiConnectionEthernet_Release(&data->etherConn);
+ cpiAddress_Destroy(&data->macAddress);
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(cpi_ConnectionEthernet)
+{
+ // 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(cpi_ConnectionEthernet)
+{
+ 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(cpi_ConnectionEthernet)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_Create);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_CreateAddMessage);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_CreateRemoveMessage);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_FromControl);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_GetPeerLinkAddress);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_GetEthertype);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_GetEthertype);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_GetInterfaceName);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_IsAddMessage);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_IsRemoveMessage);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_Equals);
+}
+
+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, cpiConnectionEthernet_Create)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ size_t beforeBalance = parcMemory_Outstanding();
+ CPIConnectionEthernet *etherConn = cpiConnectionEthernet_Create(data->ifname, data->macAddress, data->ethertype, data->symbolic);
+ cpiConnectionEthernet_Release(&etherConn);
+ size_t afterBalance = parcMemory_Outstanding();
+
+ assertTrue(afterBalance == beforeBalance,
+ "Memory imbalance on create/destroy, before %zu afer %zu",
+ beforeBalance, afterBalance);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_Equals)
+{
+ uint8_t mac_a[6] = { 1, 2, 3, 4, 5, 6 };
+ uint8_t mac_b[6] = { 9, 8, 7, 6, 5, 4 };
+
+ CPIConnectionEthernet *x = conjureObject(mac_a, 0x0123, "happy", "puppy");
+ CPIConnectionEthernet *y = conjureObject(mac_a, 0x0123, "happy", "puppy");
+ CPIConnectionEthernet *z = conjureObject(mac_a, 0x0123, "happy", "puppy");
+
+ CPIConnectionEthernet *u = conjureObject(mac_b, 0x0123, "happy", "puppy");
+ CPIConnectionEthernet *v = conjureObject(mac_a, 0x7777, "happy", "puppy");
+ CPIConnectionEthernet *w = conjureObject(mac_a, 0x0123, "sad", "kitten");
+
+ assertEqualsContract(cpiConnectionEthernet_Equals, x, y, z, u, v, w);
+
+ cpiConnectionEthernet_Release(&x);
+ cpiConnectionEthernet_Release(&y);
+ cpiConnectionEthernet_Release(&z);
+ cpiConnectionEthernet_Release(&u);
+ cpiConnectionEthernet_Release(&v);
+ cpiConnectionEthernet_Release(&w);
+}
+
+
+LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_CreateAddMessage)
+{
+ const char *truthStringFormat = "{ \"CPI_REQUEST\" : { \"SEQUENCE\" : %d, \"%s\" : { \"IFNAME\" : \"em1\", \"SYMBOLIC\" : \"conn0\", \"PEER_ADDR\" : { \"ADDRESSTYPE\" : \"LINK\", \"DATA\" : \"AQIDBAUG\" }, \"ETHERTYPE\" : 2049 } } }";
+
+ char buffer[1024];
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxControl *control = cpiConnectionEthernet_CreateAddMessage(data->etherConn);
+
+ if (ccnxControl_IsCPI(control)) {
+ PARCJSON *testJson = ccnxControl_GetJson(control);
+ assertNotNull(testJson, "Got null json from control message");
+ uint64_t seqnum = controlPlaneInterface_GetSequenceNumber(testJson);
+ sprintf(buffer, truthStringFormat, (int) seqnum, KEY_ADDETHER);
+
+ PARCJSON *truthJson = parcJSON_ParseString(buffer);
+ assertTrue(parcJSON_Equals(truthJson, testJson), "JSON not correct in Add Connection Ethernet")
+ {
+ char *a = parcJSON_ToString(testJson);
+ printf("Got: \n%s\n", a);
+ parcMemory_Deallocate((void **) &a);
+
+ printf("Expected\n%s\n", buffer);
+ }
+
+ parcJSON_Release(&truthJson);
+ }
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_CreateRemoveMessage)
+{
+ const char *truthStringFormat = "{ \"CPI_REQUEST\" : { \"SEQUENCE\" : %d, \"%s\" : { \"IFNAME\" : \"em1\", \"SYMBOLIC\" : \"conn0\", \"PEER_ADDR\" : { \"ADDRESSTYPE\" : \"LINK\", \"DATA\" : \"AQIDBAUG\" }, \"ETHERTYPE\" : 2049 } } }";
+
+ char buffer[1024];
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxControl *control = cpiConnectionEthernet_CreateRemoveMessage(data->etherConn);
+
+ if (ccnxControl_IsCPI(control)) {
+ PARCJSON *testJson = ccnxControl_GetJson(control);
+ assertNotNull(testJson, "Got null json from control message");
+ uint64_t seqnum = controlPlaneInterface_GetSequenceNumber(testJson);
+ sprintf(buffer, truthStringFormat, (int) seqnum, KEY_REMOVEETHER);
+
+ PARCJSON *truthJson = parcJSON_ParseString(buffer);
+ assertTrue(parcJSON_Equals(truthJson, testJson), "JSON not correct in Remove Connection Ethernet")
+ {
+ char *a = parcJSON_ToString(testJson);
+ printf("Got: \n%s\n", a);
+ parcMemory_Deallocate((void **) &a);
+
+ printf("Expected\n%s\n", buffer);
+ }
+
+ parcJSON_Release(&truthJson);
+ }
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_FromControl)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxControl *addMessage = cpiConnectionEthernet_CreateAddMessage(data->etherConn);
+
+ CPIConnectionEthernet *test = cpiConnectionEthernet_FromControl(addMessage);
+
+ assertNotNull(test, "Got null object parsing json: %s\n", parcJSON_ToString(ccnxControl_GetJson(addMessage)));
+
+ assertTrue(cpiConnectionEthernet_Equals(test, data->etherConn), "Object from control did not equal true value");
+
+ cpiConnectionEthernet_Release(&test);
+ ccnxControl_Release(&addMessage);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_GetPeerLinkAddress)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CPIAddress *test = cpiConnectionEthernet_GetPeerLinkAddress(data->etherConn);
+ assertTrue(cpiAddress_Equals(test, data->macAddress), "Wrong mac address");
+}
+
+
+LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_GetEthertype)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ uint16_t test = cpiConnectionEthernet_GetEthertype(data->etherConn);
+ assertTrue(test == data->ethertype, "Wrong ethertype, got %04X expected %04X", test, data->ethertype);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_GetInterfaceName)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ const char *test = cpiConnectionEthernet_GetInterfaceName(data->etherConn);
+ assertTrue(strcmp(test, data->ifname) == 0, "Wrong interface name, got '%s' expected '%s'", test, data->ifname);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_IsAddMessage)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxControl *control = cpiConnectionEthernet_CreateAddMessage(data->etherConn);
+ bool isAdd = cpiConnectionEthernet_IsAddMessage(control);
+ ccnxControl_Release(&control);
+
+ assertTrue(isAdd, "Add Connection Ethernet message did not report as such a message.");
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_IsRemoveMessage)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxControl *control = cpiConnectionEthernet_CreateRemoveMessage(data->etherConn);
+ bool isRemove = cpiConnectionEthernet_IsRemoveMessage(control);
+ ccnxControl_Release(&control);
+
+ assertTrue(isRemove, "Remove Connection Ethernet message did not report as such a message.");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_ConnectionEthernet);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionList.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionList.c
new file mode 100644
index 00000000..c624866a
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionList.c
@@ -0,0 +1,186 @@
+/*
+ * 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 "../cpi_ConnectionList.c"
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+
+
+LONGBOW_TEST_RUNNER(cpi_ConnectionList)
+{
+ // 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(cpi_ConnectionList)
+{
+ 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(cpi_ConnectionList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionList_Append);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionList_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionList_FromJson);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionList_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, cpiConnectionList_ToJson);
+}
+
+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;
+}
+
+static CPIConnection *
+createConnectionObject(unsigned ifidx, int s_addr, uint16_t s_port, int d_addr, uint16_t d_port)
+{
+ return cpiConnection_Create(ifidx,
+ cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_family = PF_INET, .sin_addr.s_addr = s_addr, .sin_port = s_port }),
+ cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_family = PF_INET, .sin_addr.s_addr = d_addr, .sin_port = d_port }),
+ cpiConnection_TCP);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnectionList_Append)
+{
+ CPIConnectionList *list = cpiConnectionList_Create();
+ cpiConnectionList_Append(list, createConnectionObject(1, 2, 3, 4, 5));
+
+ assertTrue(parcArrayList_Size(list->listOfConnections) == 1, "got wrong size, expected %u got %zu", 1, parcArrayList_Size(list->listOfConnections));
+
+ cpiConnectionList_Destroy(&list);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnectionList_Create_Destroy)
+{
+ CPIConnectionList *list = cpiConnectionList_Create();
+ cpiConnectionList_Destroy(&list);
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after create/destroy");
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnectionList_FromJson)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform.
+#if defined(__APPLE__)
+ char truth_string[] = "{\"ConnectionList\":[{\"Connection\":{\"IFIDX\":1,\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIDAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIFAAQAAAAAAAAAAAAAAA==\"}}}]}";
+#elif defined(__linux__)
+ char truth_string[] = "{\"ConnectionList\":[{\"Connection\":{\"IFIDX\":1,\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgADAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAFAAQAAAAAAAAAAAAAAA==\"}}}]}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+ CPIConnectionList *truth_list = cpiConnectionList_Create();
+ cpiConnectionList_Append(truth_list, createConnectionObject(1, 2, 3, 4, 5));
+
+ PARCJSON *truth_json = parcJSON_ParseString(truth_string);
+ CPIConnectionList *test_list = cpiConnectionList_FromJson(truth_json);
+
+ assertTrue(cpiConnectionList_Equals(truth_list, test_list), "Lists do not match");
+
+ cpiConnectionList_Destroy(&test_list);
+ parcJSON_Release(&truth_json);
+ cpiConnectionList_Destroy(&truth_list);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnectionList_Equals)
+{
+ CPIConnectionList *list_a = cpiConnectionList_Create();
+ cpiConnectionList_Append(list_a, createConnectionObject(1, 2, 3, 4, 5));
+
+ CPIConnectionList *list_b = cpiConnectionList_Create();
+ cpiConnectionList_Append(list_b, createConnectionObject(1, 2, 3, 4, 5));
+
+ CPIConnectionList *list_c = cpiConnectionList_Create();
+ cpiConnectionList_Append(list_c, createConnectionObject(1, 2, 3, 4, 5));
+
+ CPIConnectionList *unequal = cpiConnectionList_Create();
+ cpiConnectionList_Append(unequal, createConnectionObject(99, 2, 3, 4, 5));
+ cpiConnectionList_Append(unequal, createConnectionObject(1, 99, 3, 4, 5));
+ cpiConnectionList_Append(unequal, createConnectionObject(1, 2, 99, 4, 5));
+ cpiConnectionList_Append(unequal, createConnectionObject(1, 2, 3, 99, 5));
+ cpiConnectionList_Append(unequal, createConnectionObject(1, 2, 3, 4, 99));
+
+ assertEqualsContract(cpiConnectionList_Equals, list_a, list_b, list_c, unequal);
+
+ cpiConnectionList_Destroy(&unequal);
+ cpiConnectionList_Destroy(&list_a);
+ cpiConnectionList_Destroy(&list_b);
+ cpiConnectionList_Destroy(&list_c);
+}
+
+LONGBOW_TEST_CASE(Global, cpiConnectionList_ToJson)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform.
+#if defined(__APPLE__)
+ char truth_string[] = "{\"ConnectionList\":[{\"Connection\":{\"IFIDX\":1,\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIDAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIFAAQAAAAAAAAAAAAAAA==\"}}}]}";
+#elif defined(__linux__)
+ char truth_string[] = "{\"ConnectionList\":[{\"Connection\":{\"IFIDX\":1,\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgADAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAFAAQAAAAAAAAAAAAAAA==\"}}}]}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+
+ CPIConnectionList *list = cpiConnectionList_Create();
+ cpiConnectionList_Append(list, createConnectionObject(1, 2, 3, 4, 5));
+
+ PARCJSON *json = cpiConnectionList_ToJson(list);
+ char *test = parcJSON_ToCompactString(json);
+ assertTrue(strcmp(truth_string, test) == 0, "Got wrong JSON.\nexpected: %s\ngot %s\n", truth_string, test);
+ parcMemory_Deallocate((void **) &test);
+
+ parcJSON_Release(&json);
+ cpiConnectionList_Destroy(&list);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_ConnectionList);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlFacade.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlFacade.c
new file mode 100644
index 00000000..17e04299
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlFacade.c
@@ -0,0 +1,220 @@
+/*
+ * 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 "../cpi_ControlFacade.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <ccnx/transport/common/transport_MetaMessage.h>
+
+#include <LongBow/unit-test.h>
+
+typedef struct test_data {
+ char *jsonstring;
+ PARCJSON *json;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->jsonstring = parcMemory_StringDuplicate("{ \"EMPTY\": \"NESS\" }", 100);
+ data->json = parcJSON_ParseString(data->jsonstring);
+ assertNotNull(data->json, "got null JSON from string: %s", data->jsonstring);
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ parcJSON_Release(&data->json);
+ parcMemory_Deallocate((void **) &(data->jsonstring));
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(ccnx_ControlFacade)
+{
+ // 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_ControlFacade)
+{
+ 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_ControlFacade)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_CreateControlMessage_Notification);
+
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_AssertValid);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_CreateCPI);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_CreateNotification);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_GetJson);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_IsCPI);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_IsNotification);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_Display);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_ToString);
+}
+
+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, ccnxControlFacade_CreateControlMessage_Notification)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxMetaMessage *control = ccnxControlFacade_CreateNotification(data->json);
+
+ CCNxControl *cpiControl = ccnxMetaMessage_GetControl(control);
+
+ assertNotNull(cpiControl, "Got null control message");
+
+ ccnxMetaMessage_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControlFacade_AssertValid)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *control = ccnxControlFacade_CreateCPI(data->json);
+ ccnxControlFacade_AssertValid(control);
+ ccnxTlvDictionary_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControlFacade_CreateCPI)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *control = ccnxControlFacade_CreateCPI(data->json);
+ ccnxControlFacade_AssertValid(control);
+ ccnxTlvDictionary_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControlFacade_CreateNotification)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *control = ccnxControlFacade_CreateNotification(data->json);
+ ccnxControlFacade_AssertValid(control);
+ ccnxTlvDictionary_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControlFacade_GetJson)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *control = ccnxControlFacade_CreateNotification(data->json);
+
+ PARCJSON *json = ccnxControlFacade_GetJson(control);
+
+ char *test = parcJSON_ToCompactString(json);
+ char *truth = parcJSON_ToCompactString(data->json);
+
+ assertTrue(strcmp(test, truth) == 0, "Wrong JSON\ngot %s\nexpected %s\n", test, truth);
+
+ parcMemory_Deallocate((void **) &test);
+ parcMemory_Deallocate((void **) &truth);
+ ccnxTlvDictionary_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControlFacade_IsCPI)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *control = ccnxControlFacade_CreateCPI(data->json);
+ assertTrue(ccnxControlFacade_IsCPI(control), "Notification says its not a notification");
+ ccnxTlvDictionary_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControlFacade_IsNotification)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *control = ccnxControlFacade_CreateNotification(data->json);
+ assertTrue(ccnxControlFacade_IsNotification(control), "Notification says its not a notification");
+ ccnxTlvDictionary_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControlFacade_Display)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *control = ccnxControlFacade_CreateNotification(data->json);
+ ccnxControlFacade_Display(control, 1);
+ ccnxTlvDictionary_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControlFacade_ToString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *control = ccnxControlFacade_CreateNotification(data->json);
+ char *desc = ccnxControlFacade_ToString(control);
+
+ assertNotNull(desc, "Expected a string");
+ printf("%s\n", desc);
+
+ parcMemory_Deallocate((void **) &desc);
+ ccnxTlvDictionary_Release(&control);
+}
+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_ControlFacade);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlMessage.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlMessage.c
new file mode 100644
index 00000000..82b687b2
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlMessage.c
@@ -0,0 +1,378 @@
+/*
+ * 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 "../cpi_ControlMessage.c"
+
+#include <stdio.h>
+
+#include <arpa/inet.h>
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <ccnx/api/control/cpi_InterfaceIPTunnel.h>
+
+LONGBOW_TEST_RUNNER(cpi_ControlMessage)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(cpi_ControlMessage)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(cpi_ControlMessage)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateAddRouteRequest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateAddRouteToSelfRequest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateCPIRequest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateCancelFlowRequest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateConnectionListRequest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateIPTunnelRequest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateInterfaceListRequest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreatePauseInputRequest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateRemoveRouteRequest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateRemoveRouteToSelfRequest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateRouteListRequest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_Display);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_GetAckOriginalSequenceNumber);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_GetJson);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_GetNotifyStatus);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_IsACK);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_IsCPI);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxControl_IsNotification);
+}
+
+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, ccnxControl_AcquireRelease)
+{
+ CCNxControl *control = ccnxControl_CreateInterfaceListRequest();
+ CCNxControl *reference = ccnxControl_Acquire(control);
+
+ ccnxControl_Release(&control);
+
+ assertNull(control, "Expected control to be null");
+ assertNotNull(reference, "Expected acquired reference to be non null");
+ ccnxControl_Release(&reference);
+ assertNull(reference, "Expected reference to be null");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_CreateAddRouteRequest)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+ CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(name);
+ CCNxControl *control = ccnxControl_CreateAddRouteRequest(route);
+
+ assertNotNull(control, "Expected control message to be non null");
+ assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message");
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ assertTrue(cpi_getCPIOperation2(json) == CPI_REGISTER_PREFIX,
+ "Expected operation %d got %d", CPI_REGISTER_PREFIX, cpi_getCPIOperation2(json));
+ ccnxControl_Release(&control);
+ ccnxName_Release(&name);
+ cpiRouteEntry_Destroy(&route);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_CreateAddRouteToSelfRequest)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+ CCNxControl *control = ccnxControl_CreateAddRouteToSelfRequest(name);
+
+ assertNotNull(control, "Expected control message to be non null");
+ assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message");
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ assertTrue(cpi_getCPIOperation2(json) == CPI_REGISTER_PREFIX,
+ "Expected operation %d got %d", CPI_REGISTER_PREFIX, cpi_getCPIOperation2(json));
+
+ ccnxControl_Release(&control);
+ ccnxName_Release(&name);
+}
+
+
+LONGBOW_TEST_CASE(Global, ccnxControl_CreateCancelFlowRequest)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+ CCNxControl *control = ccnxControl_CreateCancelFlowRequest(name);
+ assertNotNull(control, "Expected control message to be non null");
+ assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message");
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ assertTrue(cpi_getCPIOperation2(json) == CPI_CANCEL_FLOW,
+ "Expected operation %d got %d", CPI_CANCEL_FLOW, cpi_getCPIOperation2(json));
+
+ ccnxControl_Release(&control);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_CreatePauseInputRequest)
+{
+ CCNxControl *control = ccnxControl_CreatePauseInputRequest();
+ assertNotNull(control, "Expected control message to be non null");
+ assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message");
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ assertTrue(cpi_getCPIOperation2(json) == CPI_PAUSE,
+ "Expected operation %d got %d", CPI_PAUSE, cpi_getCPIOperation2(json));
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_CreateConnectionListRequest)
+{
+ CCNxControl *control = ccnxControl_CreateConnectionListRequest();
+ assertNotNull(control, "Expected control message to be non null");
+ assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message");
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ assertTrue(cpi_getCPIOperation2(json) == CPI_CONNECTION_LIST,
+ "Expected operation %d got %d", CPI_CONNECTION_LIST, cpi_getCPIOperation2(json));
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_CreateIPTunnelRequest)
+{
+ struct sockaddr_in sockaddr_any;
+ memset(&sockaddr_any, 0, sizeof(sockaddr_any));
+ sockaddr_any.sin_family = PF_INET;
+ sockaddr_any.sin_addr.s_addr = INADDR_ANY;
+
+ CPIAddress *source = cpiAddress_CreateFromInet(&sockaddr_any);
+
+ struct sockaddr_in sockaddr_dst;
+ memset(&sockaddr_dst, 0, sizeof(sockaddr_dst));
+ sockaddr_dst.sin_family = PF_INET;
+ sockaddr_dst.sin_port = htons(9999);
+ inet_pton(AF_INET, "127.0.0.1", &(sockaddr_dst.sin_addr));
+
+ CPIAddress *destination = cpiAddress_CreateFromInet(&sockaddr_dst);
+
+ CPIInterfaceIPTunnel *tunnel = cpiInterfaceIPTunnel_Create(0, source, destination, IPTUN_TCP, "tun0");
+ CCNxControl *control = ccnxControl_CreateIPTunnelRequest(tunnel);
+
+ assertNotNull(control, "Expected control message to be non null");
+ assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message");
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ assertTrue(cpi_getCPIOperation2(json) == CPI_CREATE_TUNNEL,
+ "Expected operation %d got %d", CPI_CREATE_TUNNEL, cpi_getCPIOperation2(json));
+
+ ccnxControl_Release(&control);
+ cpiInterfaceIPTunnel_Release(&tunnel);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_CreateInterfaceListRequest)
+{
+ CCNxControl *control = ccnxControl_CreateInterfaceListRequest();
+ assertNotNull(control, "Expected control message to be non null");
+ assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message");
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ assertTrue(cpi_getCPIOperation2(json) == CPI_INTERFACE_LIST,
+ "Expected operation %d got %d", CPI_INTERFACE_LIST, cpi_getCPIOperation2(json));
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_CreateRemoveRouteRequest)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+ CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(name);
+ CCNxControl *control = ccnxControl_CreateRemoveRouteRequest(route);
+
+ assertNotNull(control, "Expected control message to be non null");
+ assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message");
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ assertTrue(cpi_getCPIOperation2(json) == CPI_UNREGISTER_PREFIX,
+ "Expected operation %d got %d", CPI_UNREGISTER_PREFIX, cpi_getCPIOperation2(json));
+
+ ccnxControl_Release(&control);
+ ccnxName_Release(&name);
+ cpiRouteEntry_Destroy(&route);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_CreateRemoveRouteToSelfRequest)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+ CCNxControl *control = ccnxControl_CreateRemoveRouteToSelfRequest(name);
+
+ assertNotNull(control, "Expected control message to be non null");
+ assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message");
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ assertTrue(cpi_getCPIOperation2(json) == CPI_UNREGISTER_PREFIX,
+ "Expected operation %d got %d", CPI_UNREGISTER_PREFIX, cpi_getCPIOperation2(json));
+
+ ccnxControl_Release(&control);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_CreateRouteListRequest)
+{
+ CCNxControl *control = ccnxControl_CreateRouteListRequest();
+ assertNotNull(control, "Expected control message to be non null");
+ assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message");
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ assertTrue(cpi_getCPIOperation2(json) == CPI_PREFIX_REGISTRATION_LIST,
+ "Expected operation %d got %d", CPI_PREFIX_REGISTRATION_LIST, cpi_getCPIOperation2(json));
+
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_CreateCPIRequest)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+ PARCJSON *cpiRequest = cpiCancelFlow_CreateRequest(name);
+
+ CCNxControl *control = ccnxControl_CreateCPIRequest(cpiRequest);
+
+ assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message");
+
+ parcJSON_Release(&cpiRequest);
+ ccnxControl_Release(&control);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_Display)
+{
+ CCNxControl *control = ccnxControl_CreateRouteListRequest();
+ ccnxControl_Display(control, 4);
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_GetAckOriginalSequenceNumber)
+{
+ CCNxControl *control = ccnxControl_CreateRouteListRequest();
+ assertNotNull(control, "Expected control message to be non null");
+ assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message");
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ PARCJSON *jsonAck = cpiAcks_CreateAck(json);
+
+ CCNxControl *response = ccnxControl_CreateCPIRequest(jsonAck);
+
+ // Calling GetAckOriginalSequenceNumber() to make sure the path works. We don't care
+ // about the value.
+ /*uint64_t originalSequenceNumber = */ ccnxControl_GetAckOriginalSequenceNumber(response);
+
+ ccnxControl_Release(&control);
+ ccnxControl_Release(&response);
+ parcJSON_Release(&jsonAck);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_GetJson)
+{
+ CCNxControl *control = ccnxControl_CreateRouteListRequest();
+ PARCJSON *json = ccnxControl_GetJson(control);
+ assertNotNull(json, "Expected some JSON");
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_IsACK)
+{
+ CCNxControl *control = ccnxControl_CreateRouteListRequest();
+ assertNotNull(control, "Expected control message to be non null");
+ assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message");
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ PARCJSON *jsonAck = cpiAcks_CreateAck(json);
+
+ CCNxControl *response = ccnxControl_CreateCPIRequest(jsonAck);
+
+ assertTrue(ccnxControl_IsACK(response), "Expected the message to be an Ack");
+
+ ccnxControl_Release(&control);
+ ccnxControl_Release(&response);
+ parcJSON_Release(&jsonAck);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_IsCPI)
+{
+ CCNxControl *control = ccnxControl_CreateRouteListRequest();
+ assertTrue(ccnxControl_IsCPI(control), "Expected a CPI Message");
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_IsNotification)
+{
+ PARCJSON *json = parcJSON_Create();
+ CCNxMetaMessage *notification = ccnxControlFacade_CreateNotification(json);
+ CCNxControl *control = ccnxMetaMessage_GetControl(notification);
+
+ assertTrue(ccnxControl_IsNotification(control), "Expected a notification");
+ assertFalse(ccnxControl_IsCPI(control), "Did not expect a CPI command");
+
+ parcJSON_Release(&json);
+ ccnxTlvDictionary_Release(&notification);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxControl_GetNotifyStatus)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie");
+
+ NotifyStatus *expected = notifyStatus_Create(1, notifyStatusCode_CONNECTION_OPEN, name, "There's a spider behind you.");
+
+ PARCJSON *json = notifyStatus_ToJSON(expected);
+ CCNxMetaMessage *notification = ccnxControlFacade_CreateNotification(json);
+ CCNxControl *control = ccnxMetaMessage_GetControl(notification);
+
+ assertTrue(ccnxControl_IsNotification(control), "Expected a notification");
+ NotifyStatus *status = ccnxControl_GetNotifyStatus(control);
+
+ assertTrue(ccnxName_Equals(notifyStatus_GetName(expected), notifyStatus_GetName(status)), "Expected equal names");
+ assertTrue(notifyStatus_GetStatusCode(expected) == notifyStatus_GetStatusCode(status), "Expected equal status codes");
+ assertTrue(strcmp(notifyStatus_GetMessage(expected), notifyStatus_GetMessage(status)) == 0, "Expected equal messages");
+
+ parcJSON_Release(&json);
+ ccnxTlvDictionary_Release(&notification);
+ ccnxName_Release(&name);
+ notifyStatus_Release(&status);
+ notifyStatus_Release(&expected);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_ControlMessage);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Forwarding.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Forwarding.c
new file mode 100644
index 00000000..ecaa569f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Forwarding.c
@@ -0,0 +1,331 @@
+/*
+ * 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 "../cpi_Forwarding.c"
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <inttypes.h>
+
+
+
+LONGBOW_TEST_RUNNER(cpi_Forwarding)
+{
+ // 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(cpi_Forwarding)
+{
+ 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(cpi_Forwarding)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_AddRoute_1);
+ LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_AddRoute_2);
+ LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_AddRoute_3);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_AddRouteJsonTag);
+ LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_AddRouteToSelf);
+ LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_RemoveRoute);
+ LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_RemoveRouteJsonTag);
+ LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_RemoveRouteToSelf);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_RouteFromControlMessage);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_CreateRouteListRequest);
+ LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_RouteListFromControlMessage);
+}
+
+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;
+}
+
+/**
+ * Add route with all options
+ */
+LONGBOW_TEST_CASE(Global, cpiForwarding_AddRoute_1)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform.
+#if defined(__APPLE__)
+ char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"REGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200,\"LIFETIME\":[3600,0]}}}";
+#elif defined(__linux__)
+ char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"REGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200,\"LIFETIME\":[3600,0]}}}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+ char truth[1024];
+
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+
+ CCNxControl *control = ccnxControl_CreateAddRouteRequest(route);
+
+ // get its sequence number
+ uint64_t seqnum = cpi_GetSequenceNumber(control);
+ sprintf(truth, truth_format, seqnum);
+
+ PARCJSON *test_json = ccnxControl_GetJson(control);
+ char *test = parcJSON_ToCompactString(test_json);
+ assertTrue(strcasecmp(truth, test) == 0, "Expected '%s', actual '%s'", truth, test);
+ parcMemory_Deallocate((void **) &test);
+
+ ccnxControl_Release(&control);
+ cpiRouteEntry_Destroy(&route);
+ cpiAddress_Destroy(&nexthop);
+}
+
+/**
+ * Add route without lifeitme
+ */
+LONGBOW_TEST_CASE(Global, cpiForwarding_AddRoute_2)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform.
+#if defined(__APPLE__)
+ char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"REGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}";
+#elif defined(__linux__)
+ char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"REGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+ char truth[1024];
+
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost);
+ CCNxControl *control = ccnxControl_CreateAddRouteRequest(route);
+
+ // get its sequence number
+ uint64_t seqnum = cpi_GetSequenceNumber(control);
+ sprintf(truth, truth_format, seqnum);
+
+ PARCJSON *test_json = ccnxControl_GetJson(control);
+ char *test = parcJSON_ToCompactString(test_json);
+ assertTrue(strcasecmp(truth, test) == 0, "Expected '%s', actual '%s'", truth, test);
+ parcMemory_Deallocate((void **) &test);
+
+ ccnxControl_Release(&control);
+ cpiRouteEntry_Destroy(&route);
+ cpiAddress_Destroy(&nexthop);
+}
+
+/**
+ * Add route without lifeitme or nexthop
+ */
+LONGBOW_TEST_CASE(Global, cpiForwarding_AddRoute_3)
+{
+ char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"REGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}";
+ char truth[1024];
+
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost);
+ CCNxControl *control = ccnxControl_CreateAddRouteRequest(route);
+
+ // get its sequence number
+ uint64_t seqnum = cpi_GetSequenceNumber(control);
+ sprintf(truth, truth_format, seqnum);
+
+ PARCJSON *test_json = ccnxControl_GetJson(control);
+ char *test = parcJSON_ToCompactString(test_json);
+ assertTrue(strcasecmp(truth, test) == 0, "Control message json does not match, expected '%s', got '%s'", truth, test);
+ parcMemory_Deallocate((void **) &test);
+
+ ccnxControl_Release(&control);
+ cpiRouteEntry_Destroy(&route);
+}
+
+
+LONGBOW_TEST_CASE(Global, cpiForwarding_AddRouteJsonTag)
+{
+ const char *tag = cpiForwarding_AddRouteJsonTag();
+ assertTrue(strcmp(tag, cpiRegister) == 0, "cpiForwarding_AddRouteJsonTag not using defined value %s", cpiRegister);
+}
+
+LONGBOW_TEST_CASE(Global, cpiForwarding_AddRouteToSelf)
+{
+ char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"REGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":2147483647,\"FLAGS\":0,\"PROTOCOL\":\"LOCAL\",\"ROUTETYPE\":\"LONGEST\",\"COST\":0}}}";
+ char truth[1024];
+
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ CCNxControl *control = ccnxControl_CreateAddRouteToSelfRequest(prefix);
+ uint64_t seqnum = cpi_GetSequenceNumber(control);
+ sprintf(truth, truth_format, seqnum);
+
+ PARCJSON *test_json = ccnxControl_GetJson(control);
+ char *test = parcJSON_ToCompactString(test_json);
+ assertTrue(strcasecmp(truth, test) == 0, "Control message json does not match, expected '%s', got '%s'", truth, test);
+ parcMemory_Deallocate((void **) &test);
+
+ ccnxControl_Release(&control);
+ ccnxName_Release(&prefix);
+}
+
+LONGBOW_TEST_CASE(Global, cpiForwarding_RemoveRoute)
+{
+ char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"UNREGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}";
+ char truth[1024];
+
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ unsigned cost = 200;
+
+ CPIRouteEntry *route =
+ cpiRouteEntry_Create(prefix, ifidx, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost);
+
+ CCNxControl *control = ccnxControl_CreateRemoveRouteRequest(route);
+
+ // get its sequence number
+ uint64_t seqnum = cpi_GetSequenceNumber(control);
+ sprintf(truth, truth_format, seqnum);
+
+ PARCJSON *test_json = ccnxControl_GetJson(control);
+ char *test = parcJSON_ToCompactString(test_json);
+ assertTrue(strcasecmp(truth, test) == 0, "Control message json does not match, expected '%s', got '%s'", truth, test);
+ parcMemory_Deallocate((void **) &test);
+
+ ccnxControl_Release(&control);
+ cpiRouteEntry_Destroy(&route);
+}
+
+LONGBOW_TEST_CASE(Global, cpiForwarding_RemoveRouteJsonTag)
+{
+ const char *tag = cpiForwarding_RemoveRouteJsonTag();
+ assertTrue(strcmp(tag, cpiUnregister) == 0, "cpiForwarding_AddRouteJsonTag not using defined value %s", cpiUnregister);
+}
+
+LONGBOW_TEST_CASE(Global, cpiForwarding_RemoveRouteToSelf)
+{
+ char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"UNREGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":2147483647,\"FLAGS\":0,\"PROTOCOL\":\"LOCAL\",\"ROUTETYPE\":\"LONGEST\",\"COST\":0}}}";
+ char truth[1024];
+
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ CCNxControl *control = ccnxControl_CreateRemoveRouteToSelfRequest(prefix);
+
+ uint64_t seqnum = cpi_GetSequenceNumber(control);
+ sprintf(truth, truth_format, seqnum);
+
+ PARCJSON *test_json = ccnxControl_GetJson(control);
+ char *test = parcJSON_ToCompactString(test_json);
+ assertTrue(strcasecmp(truth, test) == 0, "Control message json does not match, expected '%s', got '%s'", truth, test);
+ parcMemory_Deallocate((void **) &test);
+
+ ccnxControl_Release(&control);
+ ccnxName_Release(&prefix);
+}
+
+LONGBOW_TEST_CASE(Global, cpiForwarding_RouteFromControlMessage)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost);
+ CCNxControl *control = ccnxControl_CreateAddRouteRequest(route);
+
+ CPIRouteEntry *test_route = cpiForwarding_RouteFromControlMessage(control);
+
+ assertTrue(cpiRouteEntry_Equals(route, test_route),
+ "messages not equa: expected %s got %s",
+ parcJSON_ToCompactString(cpiRouteEntry_ToJson(route)),
+ parcJSON_ToCompactString(cpiRouteEntry_ToJson(test_route)));
+
+ cpiAddress_Destroy(&nexthop);
+ cpiRouteEntry_Destroy(&route);
+ cpiRouteEntry_Destroy(&test_route);
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, cpiForwarding_CreateRouteListRequest)
+{
+ CCNxControl *control = ccnxControl_CreateRouteListRequest();
+
+ assertTrue(ccnxControl_IsCPI(control), "Control message not a CPI message");
+ assertTrue(cpi_GetMessageOperation(control) == CPI_PREFIX_REGISTRATION_LIST, "Message not a prefix regisration list");
+
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, cpiForwarding_RouteListFromControlMessage)
+{
+ CCNxControl *control = ccnxControl_CreateRouteListRequest();
+
+ CPIRouteEntryList *routeList = cpiRouteEntryList_Create();
+ PARCJSON *json = cpiRouteEntryList_ToJson(routeList);
+ CCNxControl *response = cpi_CreateResponse(control, json);
+ parcJSON_Release(&json);
+ CPIRouteEntryList *test = cpiForwarding_RouteListFromControlMessage(response);
+ assertTrue(cpiRouteEntryList_Equals(routeList, test), "Route lists not equal");
+
+ ccnxControl_Release(&control);
+ ccnxControl_Release(&response);
+ cpiRouteEntryList_Destroy(&routeList);
+ cpiRouteEntryList_Destroy(&test);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_Forwarding);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Interface.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Interface.c
new file mode 100644
index 00000000..b1c7b553
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Interface.c
@@ -0,0 +1,351 @@
+/*
+ * 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 "../cpi_Interface.c"
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+
+LONGBOW_TEST_RUNNER(cpi_Interface)
+{
+ // 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(cpi_Interface)
+{
+ 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(cpi_Interface)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ==================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_AddAddress);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_GetAddresses);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_GetMtu);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_GetInterfaceIndex);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_NameEquals_IsEqual);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_NameEquals_IsNotEqual);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_ToJson);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_FromJson);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_IsEqual);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_BothNull);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_OneNull);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_UnequalName);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_UnequalIndex);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_UnequalLoopback);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_UnequalMulticast);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_UnequalMTU);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_UnequalAddresses);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterface_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, cpiInterface_Create_Destroy)
+{
+ CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_Destroy(&iface);
+
+ assertTrue(parcSafeMemory_ReportAllocation(STDOUT_FILENO) == 0, "Memory imbalance on create/destroy");
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_AddAddress)
+{
+ CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500);
+
+ cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1));
+ assertTrue(cpiAddressList_Length(iface->addressList) == 1,
+ "Incorrect address list length, expected %u got %zu",
+ 1,
+ cpiAddressList_Length(iface->addressList));
+
+ cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(2));
+ assertTrue(cpiAddressList_Length(iface->addressList) == 2,
+ "Incorrect address list length, expected %u got %zu",
+ 2,
+ cpiAddressList_Length(iface->addressList));
+
+ cpiInterface_Destroy(&iface);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_GetAddresses)
+{
+ CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500);
+
+ cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(2));
+
+ const CPIAddressList *list = cpiInterface_GetAddresses(iface);
+ assertTrue(cpiAddressList_Length(list) == 2, "Incorrect list size, expected %u got %zu", 2, cpiAddressList_Length(list));
+ cpiInterface_Destroy(&iface);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_GetMtu)
+{
+ CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500);
+
+ unsigned test = cpiInterface_GetMTU(iface);
+ assertTrue(test == 1500, "Wrong MTU expected 1500 got %u", test);
+ cpiInterface_Destroy(&iface);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_GetInterfaceIndex)
+{
+ CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500);
+
+ cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(2));
+
+ unsigned testvalue = cpiInterface_GetInterfaceIndex(iface);
+
+ assertTrue(testvalue == 1, "Incorrect interfaceIndex, expected %u got %u", 1, testvalue);
+ cpiInterface_Destroy(&iface);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_NameEquals_IsEqual)
+{
+ CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1));
+ assertTrue(cpiInterface_NameEquals(iface, "eth0"), "name did not compare as equal");
+ cpiInterface_Destroy(&iface);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_NameEquals_IsNotEqual)
+{
+ CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1));
+ assertFalse(cpiInterface_NameEquals(iface, "eth2"), "Unequal names compare as equal");
+ cpiInterface_Destroy(&iface);
+}
+
+
+LONGBOW_TEST_CASE(Global, cpiInterface_ToJson)
+{
+ char truth[] = "{\"Interface\":{\"Name\":\"eth0\",\"Index\":1,\"Loopback\":\"true\",\"Multicast\":\"false\",\"MTU\":1500,\"Addrs\":[{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAQ==\"},{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAg==\"}]}}";
+
+ CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(2));
+
+ PARCJSON *json = cpiInterface_ToJson(iface);
+
+ char *str = parcJSON_ToCompactString(json);
+ assertTrue(strcmp(str, truth) == 0, "JSON mismatch, expected '%s' got '%s'", truth, str);
+ parcMemory_Deallocate((void **) &str);
+ parcJSON_Release(&json);
+ cpiInterface_Destroy(&iface);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_FromJson)
+{
+ CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(2));
+
+ PARCJSON *json = cpiInterface_ToJson(iface);
+
+ CPIInterface *test_iface = cpiInterface_FromJson(json);
+
+ assertTrue(cpiInterface_Equals(iface, test_iface), "Interface from json not equal to truth");
+
+ cpiInterface_Destroy(&test_iface);
+ cpiInterface_Destroy(&iface);
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_Equals_IsEqual)
+{
+ CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2));
+
+ CPIInterface *iface_b = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2));
+
+ assertTrue(cpiInterface_Equals(iface_a, iface_b), "Two equal interfaces did not compare equal");
+
+ cpiInterface_Destroy(&iface_b);
+ cpiInterface_Destroy(&iface_a);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_Equals_BothNull)
+{
+ assertTrue(cpiInterface_Equals(NULL, NULL), "Two NULL interfaces did not compare equal");
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_Equals_OneNull)
+{
+ CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2));
+
+ assertFalse(cpiInterface_Equals(iface_a, NULL), "One null one non-null interfaces compare equal");
+
+ cpiInterface_Destroy(&iface_a);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_Equals_UnequalName)
+{
+ CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2));
+
+ CPIInterface *iface_b = cpiInterface_Create("eth1", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2));
+
+ assertFalse(cpiInterface_Equals(iface_a, iface_b), "Two unequal interfaces compare equal");
+
+ cpiInterface_Destroy(&iface_b);
+ cpiInterface_Destroy(&iface_a);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_Equals_UnequalIndex)
+{
+ CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2));
+
+ CPIInterface *iface_b = cpiInterface_Create("eth0", 2, true, false, 1500);
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2));
+
+ assertFalse(cpiInterface_Equals(iface_a, iface_b), "Two unequal interfaces compare equal");
+
+ cpiInterface_Destroy(&iface_b);
+ cpiInterface_Destroy(&iface_a);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_Equals_UnequalLoopback)
+{
+ CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2));
+
+ CPIInterface *iface_b = cpiInterface_Create("eth0", 1, false, false, 1500);
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2));
+
+ assertFalse(cpiInterface_Equals(iface_a, iface_b), "Two unequal interfaces compare equal");
+
+ cpiInterface_Destroy(&iface_b);
+ cpiInterface_Destroy(&iface_a);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_Equals_UnequalMulticast)
+{
+ CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2));
+
+ CPIInterface *iface_b = cpiInterface_Create("eth0", 1, true, true, 1500);
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2));
+
+ assertFalse(cpiInterface_Equals(iface_a, iface_b), "Two unequal interfaces compare equal");
+
+ cpiInterface_Destroy(&iface_b);
+ cpiInterface_Destroy(&iface_a);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_Equals_UnequalMTU)
+{
+ CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2));
+
+ CPIInterface *iface_b = cpiInterface_Create("eth0", 1, true, false, 9000);
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2));
+
+ assertFalse(cpiInterface_Equals(iface_a, iface_b), "Two unequal interfaces compare equal");
+
+ cpiInterface_Destroy(&iface_b);
+ cpiInterface_Destroy(&iface_a);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_Equals_UnequalAddresses)
+{
+ CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1));
+ cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2));
+
+ CPIInterface *iface_b = cpiInterface_Create("eth0", 1, true, false, 1500);
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(3));
+ cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2));
+
+ assertFalse(cpiInterface_Equals(iface_a, iface_b), "Two unequal interfaces compare equal");
+
+ cpiInterface_Destroy(&iface_b);
+ cpiInterface_Destroy(&iface_a);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterface_ToString)
+{
+ CPIInterface *iface = cpiInterface_Create("eth0", 1, false, true, 1500);
+ cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1));
+
+ uint32_t beforeBalance = parcMemory_Outstanding();
+ char *string = cpiInterface_ToString(iface);
+ parcMemory_Deallocate((void **) &string);
+ uint32_t afterBalance = parcMemory_Outstanding();
+ cpiInterface_Destroy(&iface);
+
+ assertTrue(beforeBalance == afterBalance, "Memory leak: off by %d allocations", (int) (afterBalance - beforeBalance));
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_Interface);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceEthernet.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceEthernet.c
new file mode 100644
index 00000000..e96fc76f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceEthernet.c
@@ -0,0 +1,191 @@
+/*
+ * 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 "../cpi_InterfaceEthernet.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+
+
+LONGBOW_TEST_RUNNER(cpi_InterfaceEthernet)
+{
+ // 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(cpi_InterfaceEthernet)
+{
+ 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(cpi_InterfaceEthernet)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_GetAddresses);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_GetIndex);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_GetState);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_FromJSON);
+}
+
+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, cpiInterfaceEthernet_Copy)
+{
+ CPIAddress *addr = cpiAddress_CreateFromInterface(5);
+ CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr);
+ CPIInterfaceEthernet *ethernet = cpiInterfaceEthernet_Create(1, list);
+
+ CPIInterfaceEthernet *copy = cpiInterfaceEthernet_Copy(ethernet);
+
+ assertTrue(cpiInterfaceEthernet_GetIndex(copy) == cpiInterfaceEthernet_GetIndex(ethernet),
+ "ifidx did not match, expected %u got %u",
+ cpiInterfaceEthernet_GetIndex(ethernet),
+ cpiInterfaceEthernet_GetIndex(copy));
+
+ assertTrue(cpiInterfaceEthernet_GetState(copy) == cpiInterfaceEthernet_GetState(ethernet),
+ "states did not match, expected %d got %d",
+ cpiInterfaceEthernet_GetState(ethernet),
+ cpiInterfaceEthernet_GetState(copy));
+
+ assertTrue(cpiAddressList_Equals(cpiInterfaceEthernet_GetAddresses(copy), cpiInterfaceEthernet_GetAddresses(ethernet)), "did not get same addresses");
+
+ cpiInterfaceEthernet_Destroy(&copy);
+ cpiInterfaceEthernet_Destroy(&ethernet);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceEthernet_Create_Destroy)
+{
+ CPIInterfaceEthernet *ethernet = cpiInterfaceEthernet_Create(1, cpiAddressList_Create());
+ cpiInterfaceEthernet_Destroy(&ethernet);
+
+ assertTrue(parcMemory_Outstanding() == 0, "Imbalance after destroying");
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceEthernet_GetAddresses)
+{
+ CPIAddress *addr = cpiAddress_CreateFromInterface(5);
+ CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr);
+ CPIInterfaceEthernet *ethernet = cpiInterfaceEthernet_Create(1, list);
+
+ const CPIAddressList *test = cpiInterfaceEthernet_GetAddresses(ethernet);
+ assertTrue(cpiAddressList_Equals(list, test), "Address lists did not match");
+
+ cpiInterfaceEthernet_Destroy(&ethernet);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceEthernet_GetIndex)
+{
+ CPIAddress *addr = cpiAddress_CreateFromInterface(5);
+ CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr);
+ CPIInterfaceEthernet *ethernet = cpiInterfaceEthernet_Create(1, list);
+
+ assertTrue(cpiInterfaceEthernet_GetIndex(ethernet) == 1, "ifidx did not match");
+
+ cpiInterfaceEthernet_Destroy(&ethernet);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceEthernet_GetState)
+{
+ CPIAddress *addr = cpiAddress_CreateFromInterface(5);
+ CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr);
+ CPIInterfaceEthernet *ethernet = cpiInterfaceEthernet_Create(1, list);
+
+ assertTrue(cpiInterfaceEthernet_GetState(ethernet) == CPI_IFACE_UNKNOWN, "state did not match");
+
+ cpiInterfaceEthernet_SetState(ethernet, CPI_IFACE_UP);
+ assertTrue(cpiInterfaceEthernet_GetState(ethernet) == CPI_IFACE_UP, "state did not match");
+
+ cpiInterfaceEthernet_SetState(ethernet, CPI_IFACE_DOWN);
+ assertTrue(cpiInterfaceEthernet_GetState(ethernet) == CPI_IFACE_DOWN, "state did not match");
+
+ cpiInterfaceEthernet_Destroy(&ethernet);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceEthernet_ToJSON)
+{
+ char truth_json_str[] = "{\"ETHERNET\":{\"IFIDX\":1,\"ADDRS\":[{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAABQ==\"},{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAADw==\"}]}}";
+
+ CPIAddress *addr5 = cpiAddress_CreateFromInterface(5);
+ CPIAddress *addr15 = cpiAddress_CreateFromInterface(15);
+ CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Append(cpiAddressList_Create(), addr5), addr15);
+
+ CPIInterfaceEthernet *ethernet = cpiInterfaceEthernet_Create(1, list);
+
+ PARCJSON *test_json = cpiInterfaceEthernet_ToJson(ethernet);
+ char *test_json_str = parcJSON_ToCompactString(test_json);
+ assertTrue(strcmp(truth_json_str, test_json_str) == 0, "JSON strings do not match");
+
+ parcMemory_Deallocate((void **) &test_json_str);
+ parcJSON_Release(&test_json);
+ cpiInterfaceEthernet_Destroy(&ethernet);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceEthernet_FromJSON)
+{
+ char truth_json_str[] = "{\"ETHERNET\":{\"IFIDX\":1,\"STATE\":\"UP\",\"ADDRS\":[{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAABQ==\"},{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAADw==\"}]}}";
+
+ CPIAddress *addr5 = cpiAddress_CreateFromInterface(5);
+ CPIAddress *addr15 = cpiAddress_CreateFromInterface(15);
+ CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Append(cpiAddressList_Create(), addr5), addr15);
+
+ CPIInterfaceEthernet *truth = cpiInterfaceEthernet_Create(1, list);
+ cpiInterfaceEthernet_SetState(truth, CPI_IFACE_UP);
+
+ PARCJSON *json = parcJSON_ParseString(truth_json_str);
+
+ CPIInterfaceEthernet *test = cpiInterfaceEthernet_CreateFromJson(json);
+ assertTrue(cpiInterfaceEthernet_Equals(truth, test), "Ethernet interfaces do not match");
+
+ parcJSON_Release(&json);
+ cpiInterfaceEthernet_Destroy(&truth);
+ cpiInterfaceEthernet_Destroy(&test);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_InterfaceEthernet);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceGeneric.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceGeneric.c
new file mode 100644
index 00000000..d427bb78
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceGeneric.c
@@ -0,0 +1,157 @@
+/*
+ * 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 "../cpi_InterfaceGeneric.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+
+LONGBOW_TEST_RUNNER(cpi_InterfaceGeneric)
+{
+ // 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(cpi_InterfaceGeneric)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(cpi_InterfaceGeneric)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceGeneric_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceGeneric_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceGeneric_GetAddresses);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceGeneric_GetIndex);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceGeneric_GetState);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceGeneric_BuildString);
+}
+
+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, cpiInterfaceGeneric_Copy)
+{
+ CPIAddress *addr = cpiAddress_CreateFromInterface(5);
+ CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr);
+ CPIInterfaceGeneric *Generic = cpiInterfaceGeneric_Create(1, list);
+
+ CPIInterfaceGeneric *copy = cpiInterfaceGeneric_Copy(Generic);
+
+ assertTrue(copy->ifidx == Generic->ifidx, "ifidx did not match, expected %u got %u", Generic->ifidx, copy->ifidx);
+ assertTrue(copy->state == Generic->state, "states did not match, expected %d got %d", Generic->state, copy->state);
+ assertTrue(cpiAddressList_Equals(copy->addresses, Generic->addresses), "did not get same addresses");
+
+ cpiInterfaceGeneric_Destroy(&copy);
+ cpiInterfaceGeneric_Destroy(&Generic);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceGeneric_Create_Destroy)
+{
+ CPIInterfaceGeneric *Generic = cpiInterfaceGeneric_Create(1, cpiAddressList_Create());
+ cpiInterfaceGeneric_Destroy(&Generic);
+
+ assertTrue(parcMemory_Outstanding() == 0, "Imbalance after destroying");
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceGeneric_GetAddresses)
+{
+ CPIAddress *addr = cpiAddress_CreateFromInterface(5);
+ CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr);
+ CPIInterfaceGeneric *Generic = cpiInterfaceGeneric_Create(1, list);
+
+ const CPIAddressList *test = cpiInterfaceGeneric_GetAddresses(Generic);
+ assertTrue(cpiAddressList_Equals(list, test), "Address lists did not match");
+
+ cpiInterfaceGeneric_Destroy(&Generic);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceGeneric_GetIndex)
+{
+ CPIAddress *addr = cpiAddress_CreateFromInterface(5);
+ CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr);
+ CPIInterfaceGeneric *Generic = cpiInterfaceGeneric_Create(1, list);
+
+ assertTrue(cpiInterfaceGeneric_GetIndex(Generic) == 1, "ifidx did not match");
+
+ cpiInterfaceGeneric_Destroy(&Generic);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceGeneric_GetState)
+{
+ CPIAddress *addr = cpiAddress_CreateFromInterface(5);
+ CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr);
+ CPIInterfaceGeneric *Generic = cpiInterfaceGeneric_Create(1, list);
+
+ assertTrue(cpiInterfaceGeneric_GetState(Generic) == CPI_IFACE_UNKNOWN, "state did not match");
+
+ cpiInterfaceGeneric_SetState(Generic, CPI_IFACE_UP);
+ assertTrue(cpiInterfaceGeneric_GetState(Generic) == CPI_IFACE_UP, "state did not match");
+
+ cpiInterfaceGeneric_SetState(Generic, CPI_IFACE_DOWN);
+ assertTrue(cpiInterfaceGeneric_GetState(Generic) == CPI_IFACE_DOWN, "state did not match");
+
+ cpiInterfaceGeneric_Destroy(&Generic);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceGeneric_BuildString)
+{
+ CPIAddressList *addrs = cpiAddressList_Create();
+ cpiAddressList_Append(addrs, cpiAddress_CreateFromInterface(1));
+ cpiAddressList_Append(addrs, cpiAddress_CreateFromInterface(2));
+
+ CPIInterfaceGeneric *generic = cpiInterfaceGeneric_Create(1, addrs);
+
+ uint32_t beforeBalance = parcMemory_Outstanding();
+ PARCBufferComposer *composer = cpiInterfaceGeneric_BuildString(generic, parcBufferComposer_Create());
+ parcBufferComposer_Release(&composer);
+ uint32_t afterBalance = parcMemory_Outstanding();
+
+ cpiInterfaceGeneric_Destroy(&generic);
+
+ assertTrue(beforeBalance == afterBalance, "Memory leak in BuildString: %d", (int) (afterBalance - beforeBalance));
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_InterfaceGeneric);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnel.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnel.c
new file mode 100644
index 00000000..20a5cfc7
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnel.c
@@ -0,0 +1,224 @@
+/*
+ * 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 "../cpi_InterfaceIPTunnel.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+
+LONGBOW_TEST_RUNNER(cpi_InterfaceIPTunnel)
+{
+ // 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(cpi_InterfaceIPTunnel)
+{
+ 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(cpi_InterfaceIPTunnel)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_GetAddresses);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_GetIndex);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_GetState);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_FromJSON);
+}
+
+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, cpiInterfaceIPTunnel_Copy)
+{
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_TCP, "tun0");
+
+ CPIInterfaceIPTunnel *copy = cpiInterfaceIPTunnel_Copy(iptun);
+
+ assertTrue(cpiInterfaceIPTunnel_GetIndex(copy) == cpiInterfaceIPTunnel_GetIndex(iptun),
+ "ifidx did not match, expected %u got %u",
+ cpiInterfaceIPTunnel_GetIndex(iptun),
+ cpiInterfaceIPTunnel_GetIndex(copy));
+
+ assertTrue(cpiInterfaceIPTunnel_GetState(copy) == cpiInterfaceIPTunnel_GetState(iptun),
+ "states did not match, expected %d got %d",
+ cpiInterfaceIPTunnel_GetState(iptun),
+ cpiInterfaceIPTunnel_GetState(copy));
+
+ assertTrue(cpiAddress_Equals(cpiInterfaceIPTunnel_GetSourceAddress(copy), cpiInterfaceIPTunnel_GetSourceAddress(iptun)),
+ "did not get same source address");
+ assertTrue(cpiAddress_Equals(cpiInterfaceIPTunnel_GetDestinationAddress(copy), cpiInterfaceIPTunnel_GetDestinationAddress(iptun)),
+ "did not get same destination address");
+
+ assertTrue(cpiInterfaceIPTunnel_GetTunnelType(copy) == cpiInterfaceIPTunnel_GetTunnelType(iptun),
+ "did not get same tunnel types!");
+
+ assertNotNull(copy->symbolic, "Copy has null symbolic name");
+ assertTrue(strcmp(iptun->symbolic, copy->symbolic) == 0, "symbolics name wrong expected '%s' got '%s'",
+ iptun->symbolic, copy->symbolic);
+
+ cpiInterfaceIPTunnel_Release(&copy);
+ cpiInterfaceIPTunnel_Release(&iptun);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnel_Create_Destroy)
+{
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_GRE, "tun0");
+ cpiInterfaceIPTunnel_Release(&iptun);
+
+ assertTrue(parcMemory_Outstanding() == 0, "Imbalance after destroying");
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnel_GetAddresses)
+{
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_TCP, "tun0");
+
+ const CPIAddress *test;
+
+ test = cpiInterfaceIPTunnel_GetSourceAddress(iptun);
+ assertTrue(cpiAddress_Equals(src, test), "Address lists did not match");
+
+ test = cpiInterfaceIPTunnel_GetDestinationAddress(iptun);
+ assertTrue(cpiAddress_Equals(dst, test), "Address lists did not match");
+
+ cpiInterfaceIPTunnel_Release(&iptun);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnel_GetIndex)
+{
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_TCP, "tun0");
+
+ assertTrue(cpiInterfaceIPTunnel_GetIndex(iptun) == 1, "ifidx did not match");
+
+ cpiInterfaceIPTunnel_Release(&iptun);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnel_GetState)
+{
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_TCP, "tun0");
+
+ assertTrue(cpiInterfaceIPTunnel_GetState(iptun) == CPI_IFACE_UNKNOWN, "state did not match");
+
+ cpiInterfaceIPTunnel_SetState(iptun, CPI_IFACE_UP);
+ assertTrue(cpiInterfaceIPTunnel_GetState(iptun) == CPI_IFACE_UP, "state did not match");
+
+ cpiInterfaceIPTunnel_SetState(iptun, CPI_IFACE_DOWN);
+ assertTrue(cpiInterfaceIPTunnel_GetState(iptun) == CPI_IFACE_DOWN, "state did not match");
+
+ cpiInterfaceIPTunnel_Release(&iptun);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnel_ToJSON)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform.
+#if defined(__APPLE__)
+ char *expected = "{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAgHBgUAAAAAAAAAAA==\"}}}";
+#elif defined(__linux__)
+ char *expected = "{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAgHBgUAAAAAAAAAAA==\"}}}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_TCP, "tun0");
+
+ PARCJSON *test_json = cpiInterfaceIPTunnel_ToJson(iptun);
+
+ char *actual = parcJSON_ToCompactString(test_json);
+ assertEqualStrings(expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSON_Release(&test_json);
+ cpiInterfaceIPTunnel_Release(&iptun);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnel_FromJSON)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform.
+#if defined(__APPLE__)
+ char truth_json_str[] = "{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"STATE\":\"UP\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAgHBgUAAAAAAAAAAA==\"}}}";
+#elif defined(__linux__)
+ char truth_json_str[] = "{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"STATE\":\"UP\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAgHBgUAAAAAAAAAAA==\"}}}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+
+ CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }));
+ CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 }));
+ CPIInterfaceIPTunnel *truth = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_TCP, "tun0");
+ cpiInterfaceIPTunnel_SetState(truth, CPI_IFACE_UP);
+
+ PARCJSON *json = parcJSON_ParseString(truth_json_str);
+
+ CPIInterfaceIPTunnel *test = cpiInterfaceIPTunnel_CreateFromJson(json);
+ assertTrue(cpiInterfaceIPTunnel_Equals(truth, test), "IPTunnel interfaces do not match");
+
+ parcJSON_Release(&json);
+ cpiInterfaceIPTunnel_Release(&truth);
+ cpiInterfaceIPTunnel_Release(&test);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_InterfaceIPTunnel);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnelList.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnelList.c
new file mode 100644
index 00000000..956ac4c3
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnelList.c
@@ -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.
+ */
+
+#include "../cpi_InterfaceIPTunnelList.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+
+LONGBOW_TEST_RUNNER(cpi_InterfaceIPTunnelList)
+{
+ // 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(cpi_InterfaceIPTunnelList)
+{
+ 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(cpi_InterfaceIPTunnelList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnelList_Append);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnelList_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnelList_FromJson);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnelList_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnelList_ToJson);
+}
+
+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;
+}
+
+static CPIInterfaceIPTunnel *
+createTunnelObject(unsigned ifidx, int s_addr, uint16_t s_port, int d_addr, uint16_t d_port)
+{
+ return cpiInterfaceIPTunnel_Create(ifidx,
+ cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_family = PF_INET, .sin_addr.s_addr = s_addr, .sin_port = s_port }),
+ cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_family = PF_INET, .sin_addr.s_addr = d_addr, .sin_port = d_port }),
+ IPTUN_TCP, "tun0");
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnelList_Append)
+{
+ CPIInterfaceIPTunnelList *list = cpiInterfaceIPTunnelList_Create();
+ cpiInterfaceIPTunnelList_Append(list, createTunnelObject(1, 2, 3, 4, 5));
+
+ assertTrue(parcArrayList_Size(list->listOfTunnels) == 1, "got wrong size, expected %u got %zu", 1, parcArrayList_Size(list->listOfTunnels));
+
+ cpiInterfaceIPTunnelList_Destroy(&list);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnelList_Create_Destroy)
+{
+ CPIInterfaceIPTunnelList *list = cpiInterfaceIPTunnelList_Create();
+ cpiInterfaceIPTunnelList_Destroy(&list);
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after create/destroy");
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnelList_FromJson)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform.
+#if defined(__APPLE__)
+ char truth_string[] = "{\"TunnelList\":[{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIDAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIFAAQAAAAAAAAAAAAAAA==\"}}}]}";
+#elif defined(__linux__)
+ char truth_string[] = "{\"TunnelList\":[{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgADAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAFAAQAAAAAAAAAAAAAAA==\"}}}]}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+
+ CPIInterfaceIPTunnelList *truth_list = cpiInterfaceIPTunnelList_Create();
+ cpiInterfaceIPTunnelList_Append(truth_list, createTunnelObject(1, 2, 3, 4, 5));
+
+ PARCJSON *truth_json = parcJSON_ParseString(truth_string);
+ CPIInterfaceIPTunnelList *test_list = cpiInterfaceIPTunnelList_FromJson(truth_json);
+
+ assertTrue(cpiInterfaceIPTunnelList_Equals(truth_list, test_list), "Lists do not match");
+
+ cpiInterfaceIPTunnelList_Destroy(&test_list);
+ parcJSON_Release(&truth_json);
+ cpiInterfaceIPTunnelList_Destroy(&truth_list);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnelList_Equals)
+{
+ CPIInterfaceIPTunnelList *list_a = cpiInterfaceIPTunnelList_Create();
+ cpiInterfaceIPTunnelList_Append(list_a, createTunnelObject(1, 2, 3, 4, 5));
+
+ CPIInterfaceIPTunnelList *list_b = cpiInterfaceIPTunnelList_Create();
+ cpiInterfaceIPTunnelList_Append(list_b, createTunnelObject(1, 2, 3, 4, 5));
+
+ CPIInterfaceIPTunnelList *list_c = cpiInterfaceIPTunnelList_Create();
+ cpiInterfaceIPTunnelList_Append(list_c, createTunnelObject(1, 2, 3, 4, 5));
+
+ CPIInterfaceIPTunnelList *unequal = cpiInterfaceIPTunnelList_Create();
+ cpiInterfaceIPTunnelList_Append(unequal, createTunnelObject(99, 2, 3, 4, 5));
+ cpiInterfaceIPTunnelList_Append(unequal, createTunnelObject(1, 99, 3, 4, 5));
+ cpiInterfaceIPTunnelList_Append(unequal, createTunnelObject(1, 2, 99, 4, 5));
+ cpiInterfaceIPTunnelList_Append(unequal, createTunnelObject(1, 2, 3, 99, 5));
+ cpiInterfaceIPTunnelList_Append(unequal, createTunnelObject(1, 2, 3, 4, 99));
+
+ assertEqualsContract(cpiInterfaceIPTunnelList_Equals, list_a, list_b, list_c, unequal);
+
+ cpiInterfaceIPTunnelList_Destroy(&unequal);
+ cpiInterfaceIPTunnelList_Destroy(&list_a);
+ cpiInterfaceIPTunnelList_Destroy(&list_b);
+ cpiInterfaceIPTunnelList_Destroy(&list_c);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnelList_ToJson)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform.
+#if defined(__APPLE__)
+ char truth_string[] = "{\"TunnelList\":[{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIDAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIFAAQAAAAAAAAAAAAAAA==\"}}}]}";
+#elif defined(__linux__)
+ char truth_string[] = "{\"TunnelList\":[{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgADAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAFAAQAAAAAAAAAAAAAAA==\"}}}]}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+ CPIInterfaceIPTunnelList *list = cpiInterfaceIPTunnelList_Create();
+ cpiInterfaceIPTunnelList_Append(list, createTunnelObject(1, 2, 3, 4, 5));
+
+ PARCJSON *json = cpiInterfaceIPTunnelList_ToJson(list);
+ char *test = parcJSON_ToCompactString(json);
+ assertTrue(strcmp(truth_string, test) == 0, "Got wrong JSON.\nexpected: %s\ngot %s\n", truth_string, test);
+ parcMemory_Deallocate((void **) &test);
+
+ parcJSON_Release(&json);
+ cpiInterfaceIPTunnelList_Destroy(&list);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_InterfaceIPTunnelList);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceSet.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceSet.c
new file mode 100644
index 00000000..d87149bf
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceSet.c
@@ -0,0 +1,243 @@
+/*
+ * 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 "../cpi_InterfaceSet.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+
+
+LONGBOW_TEST_RUNNER(cpi_InterfaceSet)
+{
+ // 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(cpi_InterfaceSet)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(cpi_InterfaceSet)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_Add_Single);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_Add_TwoUnique);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_Add_TwoSame);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_FromJson);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_GetByInterfaceIndex);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_GetByName);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_GetByOrdinalIndex);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_Length);
+ LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_ToJson);
+}
+
+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, cpiInterfaceSet_Add_Single)
+{
+ CPIInterfaceSet *set = cpiInterfaceSet_Create();
+
+ CPIInterface *iface = cpiInterface_Create("eth0", 11, false, true, 1500);
+ bool success = cpiInterfaceSet_Add(set, iface);
+ assertTrue(success, "Adding one interface did not succeed");
+ assertTrue(parcArrayList_Size(set->listOfInterfaces) == 1, "List wrong size, expected %u got %zu", 1, parcArrayList_Size(set->listOfInterfaces));
+ cpiInterfaceSet_Destroy(&set);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceSet_Add_TwoUnique)
+{
+ CPIInterfaceSet *set = cpiInterfaceSet_Create();
+
+ CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500);
+ bool success = cpiInterfaceSet_Add(set, iface0);
+ assertTrue(success, "Adding one interface did not succeed");
+
+ CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500);
+ success = cpiInterfaceSet_Add(set, iface1);
+ assertTrue(success, "Adding second interface did not succeed");
+
+ assertTrue(parcArrayList_Size(set->listOfInterfaces) == 2, "List wrong size, expected %u got %zu", 2, parcArrayList_Size(set->listOfInterfaces));
+ cpiInterfaceSet_Destroy(&set);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceSet_Add_TwoSame)
+{
+ CPIInterfaceSet *set = cpiInterfaceSet_Create();
+
+ CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500);
+ bool success = cpiInterfaceSet_Add(set, iface0);
+ assertTrue(success, "Adding one interface did not succeed");
+
+ CPIInterface *iface1 = cpiInterface_Create("eth0", 11, false, true, 1500);
+ success = cpiInterfaceSet_Add(set, iface1);
+ assertFalse(success, "Adding second interface duplicate interface should have failed");
+ cpiInterface_Destroy(&iface1);
+
+ assertTrue(parcArrayList_Size(set->listOfInterfaces) == 1, "List wrong size, expected %u got %zu", 1, parcArrayList_Size(set->listOfInterfaces));
+ cpiInterfaceSet_Destroy(&set);
+}
+
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceSet_Create_Destroy)
+{
+ CPIInterfaceSet *set = cpiInterfaceSet_Create();
+ cpiInterfaceSet_Destroy(&set);
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after create/destroy");
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceSet_GetByInterfaceIndex)
+{
+ CPIInterfaceSet *set = cpiInterfaceSet_Create();
+
+ CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500);
+ cpiInterfaceSet_Add(set, iface0);
+
+ CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500);
+ cpiInterfaceSet_Add(set, iface1);
+
+ CPIInterface *test = cpiInterfaceSet_GetByInterfaceIndex(set, 11);
+
+ assertTrue(cpiInterface_Equals(test, iface0), "Did not get back right interface");
+
+ cpiInterfaceSet_Destroy(&set);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceSet_GetByName)
+{
+ CPIInterfaceSet *set = cpiInterfaceSet_Create();
+
+ CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500);
+ cpiInterfaceSet_Add(set, iface0);
+
+ CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500);
+ cpiInterfaceSet_Add(set, iface1);
+
+ CPIInterface *test = cpiInterfaceSet_GetByName(set, "eth0");
+
+ assertTrue(cpiInterface_Equals(test, iface0), "Did not get back right interface");
+
+ cpiInterfaceSet_Destroy(&set);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceSet_GetByOrdinalIndex)
+{
+ CPIInterfaceSet *set = cpiInterfaceSet_Create();
+
+ CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500);
+ cpiInterfaceSet_Add(set, iface0);
+
+ CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500);
+ cpiInterfaceSet_Add(set, iface1);
+
+ CPIInterface *test = cpiInterfaceSet_GetByOrdinalIndex(set, 0);
+
+ assertTrue(cpiInterface_Equals(test, iface0), "Did not get back right interface");
+
+ cpiInterfaceSet_Destroy(&set);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceSet_Length)
+{
+ CPIInterfaceSet *set = cpiInterfaceSet_Create();
+
+ CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500);
+ cpiInterfaceSet_Add(set, iface0);
+
+ CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500);
+ cpiInterfaceSet_Add(set, iface1);
+
+ size_t length = cpiInterfaceSet_Length(set);
+
+ assertTrue(length == 2, "Wrong length, expected %u got %zu", 2, length);
+
+ cpiInterfaceSet_Destroy(&set);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceSet_ToJson)
+{
+ char truth[] = "{\"Interfaces\":[{\"Interface\":{\"Name\":\"eth0\",\"Index\":11,\"Loopback\":\"false\",\"Multicast\":\"true\",\"MTU\":1500,\"Addrs\":[]}},{\"Interface\":{\"Name\":\"eth1\",\"Index\":12,\"Loopback\":\"false\",\"Multicast\":\"true\",\"MTU\":1500,\"Addrs\":[]}}]}";
+
+ CPIInterfaceSet *set = cpiInterfaceSet_Create();
+
+ CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500);
+ cpiInterfaceSet_Add(set, iface0);
+
+ CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500);
+ cpiInterfaceSet_Add(set, iface1);
+
+ PARCJSON *json = cpiInterfaceSet_ToJson(set);
+ char *str = parcJSON_ToCompactString(json);
+ assertTrue(strcasecmp(truth, str) == 0, "Json wrong, expected '%s' got '%s'", truth, str);
+ parcMemory_Deallocate((void **) &str);
+
+ parcJSON_Release(&json);
+ cpiInterfaceSet_Destroy(&set);
+}
+
+LONGBOW_TEST_CASE(Global, cpiInterfaceSet_FromJson)
+{
+ CPIInterfaceSet *set = cpiInterfaceSet_Create();
+
+ CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500);
+ cpiInterfaceSet_Add(set, iface0);
+
+ CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500);
+ cpiInterfaceSet_Add(set, iface1);
+
+ PARCJSON *json = cpiInterfaceSet_ToJson(set);
+
+ CPIInterfaceSet *test_set = cpiInterfaceSet_FromJson(json);
+
+ assertTrue(cpiInterfaceSet_Equals(set, test_set), "CPIInterfaceSet from json did not equal truth set");
+
+ parcJSON_Release(&json);
+ cpiInterfaceSet_Destroy(&set);
+ cpiInterfaceSet_Destroy(&test_set);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_InterfaceSet);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceTypes.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceTypes.c
new file mode 100644
index 00000000..a207eecd
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceTypes.c
@@ -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.
+ */
+
+#include "../cpi_InterfaceType.c"
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+
+
+LONGBOW_TEST_RUNNER(cpi_InterfaceTypes)
+{
+ // 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(cpi_InterfaceTypes)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(cpi_InterfaceTypes)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
+
+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_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(cpi_InterfaceTypes);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Listener.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Listener.c
new file mode 100644
index 00000000..5bd5a534
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Listener.c
@@ -0,0 +1,384 @@
+/*
+ * 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 "../cpi_Listener.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+typedef struct test_data {
+ CPIListener *listener;
+
+ // the truth values of the connection
+ uint8_t macArray[6];
+ CPIAddress *macAddress;
+ uint16_t ethertype;
+ char ifname[16];
+ char symbolic[16];
+} TestData;
+
+static CPIListener *
+_conjureIPObject(CPIInterfaceIPTunnelType type, const char *addressString, uint16_t port, const char *symbolic)
+{
+ struct sockaddr_in sin;
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ int result = inet_aton(addressString, &sin.sin_addr);
+ assertTrue(result == 1, "failed inet_aton: (%d) %s", errno, strerror(errno));
+
+ CPIAddress *address = cpiAddress_CreateFromInet(&sin);
+ CPIListener *listener = cpiListener_CreateIP(type, address, symbolic);
+ cpiAddress_Destroy(&address);
+
+ return listener;
+}
+
+LONGBOW_TEST_RUNNER(cpi_ConnectionEthernet)
+{
+ // 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(cpi_ConnectionEthernet)
+{
+ 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(cpi_ConnectionEthernet)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_CreateEther);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_CreateIP);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_Equals_Ether);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_Equals_IP);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_CreateAddMessage);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_CreateRemoveMessage);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_IsAddMessage);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_IsRemoveMessage);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_FromControl_Ether);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_FromControl_IP);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_IsEtherEncap);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_IsIPEncap);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_GetEtherType);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_GetInterfaceName);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_GetSymbolicName);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_GetAddress);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_IsProtocolUdp);
+ LONGBOW_RUN_TEST_CASE(Global, cpiListener_IsProtocolTcp);
+}
+
+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, cpiListener_CreateEther)
+{
+ CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ assertNotNull(listener, "Got null IP based listener");
+ cpiListener_Release(&listener);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_CreateIP)
+{
+ CPIListener *listener = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy");
+ assertNotNull(listener, "Got null IP based listener");
+ cpiListener_Release(&listener);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_Equals_Ether)
+{
+ CPIListener *x = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ CPIListener *y = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ CPIListener *z = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+
+ CPIListener *t = cpiListener_CreateEther("eth1", 0x0801, "puppy");
+ CPIListener *u = cpiListener_CreateEther("eth0", 0x0802, "puppy");
+ CPIListener *v = cpiListener_CreateEther("eth0", 0x0801, "kitten");
+
+ assertEqualsContract(cpiListener_Equals, x, y, z, t, u, v);
+
+ cpiListener_Release(&x);
+ cpiListener_Release(&y);
+ cpiListener_Release(&z);
+ cpiListener_Release(&t);
+ cpiListener_Release(&u);
+ cpiListener_Release(&v);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_Equals_IP)
+{
+ CPIListener *x = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy");
+ CPIListener *y = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy");
+ CPIListener *z = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy");
+
+ CPIListener *t = _conjureIPObject(IPTUN_TCP, "127.0.0.1", 9596, "puppy");
+ CPIListener *u = _conjureIPObject(IPTUN_UDP, "127.0.2.1", 9596, "puppy");
+ CPIListener *v = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 1111, "puppy");
+ CPIListener *w = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "kitten");
+
+ assertEqualsContract(cpiListener_Equals, x, y, z, t, u, v, w);
+
+ cpiListener_Release(&x);
+ cpiListener_Release(&y);
+ cpiListener_Release(&z);
+ cpiListener_Release(&t);
+ cpiListener_Release(&u);
+ cpiListener_Release(&v);
+ cpiListener_Release(&w);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_CreateAddMessage)
+{
+ const char *truthFormat = "{\"CPI_REQUEST\":{\"SEQUENCE\":%d,\"%s\":{\"IFNAME\":\"eth0\",\"ETHERTYPE\":2049,\"SYMBOLIC\":\"puppy\"}}}";
+
+ char buffer[1024];
+
+ // Create the add message
+ CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ CCNxControl *control = cpiListener_CreateAddMessage(listener);
+ assertNotNull(control, "Got null control message");
+
+ // extract the sequence number to put in the truth string
+ PARCJSON *json = ccnxControl_GetJson(control);
+ uint64_t seqnum = controlPlaneInterface_GetSequenceNumber(json);
+ sprintf(buffer, truthFormat, (int) seqnum, KEY_ADDLISTENER);
+
+ char *testString = parcJSON_ToCompactString(json);
+ assertTrue(strcmp(buffer, testString) == 0, "Got wrong JSON, expected\n%s\nGot\n%s\n", buffer, testString);
+ parcMemory_Deallocate((void **) &testString);
+
+ ccnxControl_Release(&control);
+ cpiListener_Release(&listener);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_CreateRemoveMessage)
+{
+#if defined(__APPLE__)
+ const char *truthFormat = "{\"CPI_REQUEST\":{\"SEQUENCE\":%d,\"%s\":{\"IPROTO\":\"UDP\",\"ADDR\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIlfH8AAAEAAAAAAAAAAA==\"},\"SYMBOLIC\":\"puppy\"}}}";
+#elif defined(__linux__)
+ const char *truthFormat = "{\"CPI_REQUEST\":{\"SEQUENCE\":%d,\"%s\":{\"IPROTO\":\"UDP\",\"ADDR\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAlfH8AAAEAAAAAAAAAAA==\"},\"SYMBOLIC\":\"puppy\"}}}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+ char buffer[1024];
+
+ // Create the remove message
+ CPIListener *listener = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy");
+ CCNxControl *control = cpiListener_CreateRemoveMessage(listener);
+ assertNotNull(control, "Got null control message");
+
+ // extract the sequence number to put in the truth string
+ PARCJSON *json = ccnxControl_GetJson(control);
+ uint64_t seqnum = controlPlaneInterface_GetSequenceNumber(json);
+ sprintf(buffer, truthFormat, (int) seqnum, KEY_REMOVELISTENER);
+
+ char *testString = parcJSON_ToCompactString(json);
+ assertTrue(strcmp(buffer, testString) == 0, "Got wrong JSON, expected\n%s\nGot\n%s\n", buffer, testString);
+ parcMemory_Deallocate((void **) &testString);
+
+ ccnxControl_Release(&control);
+ cpiListener_Release(&listener);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_IsAddMessage)
+{
+ CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ CCNxControl *control = cpiListener_CreateAddMessage(listener);
+ assertNotNull(control, "Got null control message");
+
+ bool test = cpiListener_IsAddMessage(control);
+ assertTrue(test, "Add message denies it is one.");
+
+ ccnxControl_Release(&control);
+ cpiListener_Release(&listener);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_IsRemoveMessage)
+{
+ CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ CCNxControl *control = cpiListener_CreateRemoveMessage(listener);
+ assertNotNull(control, "Got null control message");
+
+ bool test = cpiListener_IsRemoveMessage(control);
+ assertTrue(test, "Add message denies it is one.");
+
+ ccnxControl_Release(&control);
+ cpiListener_Release(&listener);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_FromControl_Ether)
+{
+ CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ CCNxControl *control = cpiListener_CreateAddMessage(listener);
+
+ CPIListener *test = cpiListener_FromControl(control);
+ assertTrue(cpiListener_Equals(listener, test), "Listeners do not match")
+ {
+ printf("Expenected:\n");
+ char *str = parcJSON_ToString(ccnxControl_GetJson(control));
+ printf(" %s\n", str);
+ parcMemory_Deallocate((void **) &str);
+
+ printf("Got:\n");
+ CCNxControl *testControl = cpiListener_CreateAddMessage(test);
+ str = parcJSON_ToString(ccnxControl_GetJson(testControl));
+ printf(" %s\n", str);
+ parcMemory_Deallocate((void **) &str);
+ ccnxControl_Release(&testControl);
+ }
+
+ ccnxControl_Release(&control);
+ cpiListener_Release(&test);
+ cpiListener_Release(&listener);
+}
+
+
+LONGBOW_TEST_CASE(Global, cpiListener_FromControl_IP)
+{
+ CPIListener *listener = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy");
+ CCNxControl *control = cpiListener_CreateAddMessage(listener);
+
+ CPIListener *test = cpiListener_FromControl(control);
+ assertTrue(cpiListener_Equals(listener, test), "Listeners do not match")
+ {
+ printf("Expenected:\n");
+ char *str = parcJSON_ToString(ccnxControl_GetJson(control));
+ printf(" %s\n", str);
+ parcMemory_Deallocate((void **) &str);
+
+ printf("Got:\n");
+ CCNxControl *testControl = cpiListener_CreateAddMessage(test);
+ str = parcJSON_ToString(ccnxControl_GetJson(testControl));
+ printf(" %s\n", str);
+ parcMemory_Deallocate((void **) &str);
+ ccnxControl_Release(&testControl);
+ }
+
+ ccnxControl_Release(&control);
+ cpiListener_Release(&test);
+ cpiListener_Release(&listener);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_IsEtherEncap)
+{
+ CPIListener *x = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ bool isTrue = cpiListener_IsEtherEncap(x);
+ assertTrue(isTrue, "Ether listener says it is not ether");
+ cpiListener_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_IsIPEncap)
+{
+ CPIListener *x = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy");
+ bool isTrue = cpiListener_IsIPEncap(x);
+ assertTrue(isTrue, "IP listener says it is not IP");
+ cpiListener_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_GetAddress)
+{
+ CPIListener *x = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy");
+ CPIAddress *test = cpiListener_GetAddress(x);
+ assertNotNull(test, "Got null address for IP listener");
+
+ struct sockaddr_in sin;
+ cpiAddress_GetInet(test, &sin);
+ assertTrue(htons(sin.sin_port) == 9596, "Wrong port expected %u got %u", 9695, htons(sin.sin_port));
+
+ uint32_t testip = htonl(sin.sin_addr.s_addr);
+ uint32_t truthip = 0x7F000001;
+
+ assertTrue(testip == truthip, "Wrong IP address expected %#08x got %#08x", truthip, testip);
+
+ cpiListener_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_GetEtherType)
+{
+ CPIListener *x = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ uint16_t test = cpiListener_GetEtherType(x);
+ assertTrue(test == 0x0801, "Wrong ethertype, got %04x expected %04x", test, 0x0801);
+ cpiListener_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_GetInterfaceName)
+{
+ CPIListener *x = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ const char *test = cpiListener_GetInterfaceName(x);
+ assertTrue(strcmp(test, "eth0") == 0, "Wrong interface name, got '%s' expected '%s'", test, "eth0");
+ cpiListener_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_GetSymbolicName)
+{
+ CPIListener *x = cpiListener_CreateEther("eth0", 0x0801, "puppy");
+ const char *test = cpiListener_GetSymbolicName(x);
+ assertTrue(strcmp(test, "puppy") == 0, "Wrong symbolic name, got '%s' expected '%s'", test, "puppy");
+ cpiListener_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_IsProtocolUdp)
+{
+ CPIListener *x = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy");
+ assertTrue(cpiListener_IsProtocolUdp(x), "UDP listener did not say it was UDP");
+ cpiListener_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, cpiListener_IsProtocolTcp)
+{
+ CPIListener *x = _conjureIPObject(IPTUN_TCP, "127.0.0.1", 9596, "puppy");
+ assertTrue(cpiListener_IsProtocolTcp(x), "TCP listener did not say it was TCP");
+ cpiListener_Release(&x);
+}
+
+// =========================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_ConnectionEthernet);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ManageLinks.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ManageLinks.c
new file mode 100644
index 00000000..381e49b1
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ManageLinks.c
@@ -0,0 +1,266 @@
+/*
+ * 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 "../cpi_ManageLinks.c"
+#include <LongBow/testing.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_Network.h>
+#include <inttypes.h>
+
+
+
+static const short testCpiManageLinks_MetisPort = 9695;
+
+LONGBOW_TEST_RUNNER(cpi_ManageLinks)
+{
+ // 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(cpi_ManageLinks)
+{
+ 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(cpi_ManageLinks)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiLinks_CreateIPTunnel);
+ LONGBOW_RUN_TEST_CASE(Global, cpiLinks_CreateInterfaceListRequest);
+ LONGBOW_RUN_TEST_CASE(Global, cpiLinks_InterfacesFromControlMessage);
+ LONGBOW_RUN_TEST_CASE(Global, cpiLinks_InterfaceIPTunnelFromControlMessage);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiLinks_CreateConnectionListRequest);
+ LONGBOW_RUN_TEST_CASE(Global, cpiLinks_ConnectionListFromControlMessage);
+}
+
+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, cpiLinks_CreateIPTunnel)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform. Note that the port number is encoded in the JSON,
+ // so if you change the port the test will fail.
+#if defined(__APPLE__)
+ char *truth_format = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"CREATE_TUNNEL\":{\"TUNNEL\":{\"IFIDX\":0,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAAAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIl338AAAEAAAAAAAAAAA==\"}}}}}";
+#elif defined(__linux__)
+ char *truth_format = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"CREATE_TUNNEL\":{\"TUNNEL\":{\"IFIDX\":0,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAAAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAl338AAAEAAAAAAAAAAA==\"}}}}}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+ // ---------------------------
+ // Tunnel addresses
+ struct sockaddr_in sockaddr_any;
+ memset(&sockaddr_any, 0, sizeof(sockaddr_any));
+ sockaddr_any.sin_family = PF_INET;
+ sockaddr_any.sin_addr.s_addr = INADDR_ANY;
+
+ CPIAddress *source = cpiAddress_CreateFromInet(&sockaddr_any);
+
+ struct sockaddr_in sockaddr_dst;
+ memset(&sockaddr_dst, 0, sizeof(sockaddr_dst));
+ sockaddr_dst.sin_family = PF_INET;
+ sockaddr_dst.sin_port = htons(testCpiManageLinks_MetisPort);
+ inet_pton(AF_INET, "127.0.0.1", &(sockaddr_dst.sin_addr));
+
+ CPIAddress *destination = cpiAddress_CreateFromInet(&sockaddr_dst);
+
+ // ---------------------------
+
+ CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(0, source, destination, IPTUN_TCP, "tun0");
+ CCNxControl *control = ccnxControl_CreateIPTunnelRequest(iptun);
+
+ char buffer[1024];
+ sprintf(buffer, truth_format, cpi_GetSequenceNumber(control));
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ char *test_string = parcJSON_ToCompactString(json);
+ assertTrue(strcmp(buffer, test_string) == 0, "JSON strings did not match.\nexpected %s\ngot %s\n", buffer, test_string);
+ parcMemory_Deallocate((void **) &test_string);
+
+ ccnxControl_Release(&control);
+ cpiInterfaceIPTunnel_Release(&iptun);
+}
+
+LONGBOW_TEST_CASE(Global, cpiLinks_CreateInterfaceListRequest)
+{
+ char template[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%llu,\"INTERFACE_LIST\":{}}}";
+ char truth[1024];
+
+ CCNxControl *control = ccnxControl_CreateInterfaceListRequest();
+
+ uint64_t seqnum = cpi_GetSequenceNumber(control);
+
+ sprintf(truth, template, seqnum);
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ char *str = parcJSON_ToCompactString(json);
+ assertTrue(strcmp(truth, str) == 0, "Did not get right json, expected '%s' got '%s'", truth, str);
+ parcMemory_Deallocate((void **) &str);
+
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, cpiLinks_InterfacesFromControlMessage)
+{
+ CCNxControl *control = ccnxControl_CreateInterfaceListRequest();
+
+ CPIInterfaceSet *truth = cpiInterfaceSet_Create();
+ CPIInterface *iface = cpiInterface_Create("eth0", 11, false, true, 1500);
+ cpiInterfaceSet_Add(truth, iface);
+
+ PARCJSON *json = cpiInterfaceSet_ToJson(truth);
+ CCNxControl *response = cpi_CreateResponse(control, json);
+ parcJSON_Release(&json);
+ CPIInterfaceSet *test = cpiLinks_InterfacesFromControlMessage(response);
+
+ assertTrue(cpiInterfaceSet_Equals(test, truth), "Interface sets not equal");
+
+ ccnxControl_Release(&response);
+ cpiInterfaceSet_Destroy(&truth);
+ cpiInterfaceSet_Destroy(&test);
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, cpiLinks_InterfaceIPTunnelFromControlMessage)
+{
+ // ---------------------------
+ // Tunnel addresses
+ struct sockaddr_in sockaddr_any;
+ memset(&sockaddr_any, 0, sizeof(sockaddr_any));
+ sockaddr_any.sin_family = PF_INET;
+ sockaddr_any.sin_addr.s_addr = INADDR_ANY;
+
+ CPIAddress *source = cpiAddress_CreateFromInet(&sockaddr_any);
+
+ struct sockaddr_in sockaddr_dst;
+ memset(&sockaddr_dst, 0, sizeof(sockaddr_dst));
+ sockaddr_dst.sin_family = PF_INET;
+ sockaddr_dst.sin_port = htons(testCpiManageLinks_MetisPort);
+ inet_pton(AF_INET, "127.0.0.1", &(sockaddr_dst.sin_addr));
+
+ CPIAddress *destination = cpiAddress_CreateFromInet(&sockaddr_dst);
+
+ // ---------------------------
+
+ CPIInterfaceIPTunnel *truth = cpiInterfaceIPTunnel_Create(0, source, destination, IPTUN_TCP, "tun0");
+ CCNxControl *control = ccnxControl_CreateIPTunnelRequest(truth);
+
+ CPIInterfaceIPTunnel *test = cpiLinks_CreateIPTunnelFromControlMessage(control);
+
+ assertTrue(cpiInterfaceIPTunnel_Equals(truth, test), "InterfaceIPTunnels do not match");
+
+ ccnxControl_Release(&control);
+ cpiInterfaceIPTunnel_Release(&test);
+ cpiInterfaceIPTunnel_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Global, cpiLinks_CreateConnectionListRequest)
+{
+ char template[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%llu,\"CONNECTION_LIST\":{}}}";
+ char truth[1024];
+
+ CCNxControl *control = ccnxControl_CreateConnectionListRequest();
+ uint64_t seqnum = cpi_GetSequenceNumber(control);
+
+ sprintf(truth, template, seqnum);
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+ char *str = parcJSON_ToCompactString(json);
+
+ assertTrue(strcmp(truth, str) == 0, "Did not get right json, expected '%s' got '%s'", truth, str);
+ parcMemory_Deallocate((void **) &str);
+
+ ccnxControl_Release(&control);
+}
+
+LONGBOW_TEST_CASE(Global, cpiLinks_ConnectionListFromControlMessage)
+{
+ // The request we'll create a response to
+ CCNxControl *request = ccnxControl_CreateConnectionListRequest();
+
+ // ---------------------------
+ // Tunnel addresses
+ struct sockaddr_in sockaddr_any;
+ memset(&sockaddr_any, 0, sizeof(sockaddr_any));
+ sockaddr_any.sin_family = PF_INET;
+ sockaddr_any.sin_addr.s_addr = INADDR_ANY;
+
+ CPIAddress *source = cpiAddress_CreateFromInet(&sockaddr_any);
+
+ struct sockaddr_in sockaddr_dst;
+ memset(&sockaddr_dst, 0, sizeof(sockaddr_dst));
+ sockaddr_dst.sin_family = PF_INET;
+ sockaddr_dst.sin_port = htons(testCpiManageLinks_MetisPort);
+ inet_pton(AF_INET, "127.0.0.1", &(sockaddr_dst.sin_addr));
+
+ CPIAddress *destination = cpiAddress_CreateFromInet(&sockaddr_dst);
+
+ // ---------------------------
+
+ CPIConnectionList *truth_list = cpiConnectionList_Create();
+ cpiConnectionList_Append(truth_list, cpiConnection_Create(0, source, destination, cpiConnection_TCP));
+
+ PARCJSON *json = cpiConnectionList_ToJson(truth_list);
+ CCNxControl *response = cpi_CreateResponse(request, json);
+ parcJSON_Release(&json);
+ CPIConnectionList *test = cpiLinks_ConnectionListFromControlMessage(response);
+
+ assertTrue(cpiConnectionList_Equals(truth_list, test), "InterfaceIPTunnels do not match");
+
+ ccnxControl_Release(&response);
+ ccnxControl_Release(&request);
+ cpiConnectionList_Destroy(&test);
+ cpiConnectionList_Destroy(&truth_list);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_ManageLinks);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_NameRouteType.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_NameRouteType.c
new file mode 100644
index 00000000..85175a7e
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_NameRouteType.c
@@ -0,0 +1,93 @@
+/*
+ * 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 "../cpi_NameRouteType.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(cpi_NameRouteType)
+{
+ // 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(cpi_NameRouteType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(cpi_NameRouteType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiNameRouteType_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, cpiNameRouteType_FromString);
+}
+
+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, cpiNameRouteType_ToString)
+{
+ int numEntries = sizeof(nameRouteTypeString) / sizeof(nameRouteTypeString[0]);
+
+ for (int i = 0; i < numEntries; i++) {
+ if (nameRouteTypeString[i].type != 0) {
+ assertTrue(cpiNameRouteType_ToString(nameRouteTypeString[i].type) != NULL, "Expected non-NULL type name");
+ }
+ }
+}
+
+LONGBOW_TEST_CASE(Global, cpiNameRouteType_FromString)
+{
+ int numEntries = sizeof(nameRouteTypeString) / sizeof(nameRouteTypeString[0]);
+
+ for (int i = 0; i < numEntries; i++) {
+ if (nameRouteTypeString[i].str != NULL) {
+ CPINameRouteType type = cpiNameRouteType_FromString(nameRouteTypeString[i].str);
+ assertTrue(type == cpiNameRouteType_DEFAULT || type == cpiNameRouteType_EXACT_MATCH || type == cpiNameRouteType_LONGEST_MATCH, "unexpected route type");
+ }
+ }
+ // Test a name that doesn't exist. (need to catch the trap) Case 1034
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_NameRouteType);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Registration.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Registration.c
new file mode 100644
index 00000000..6f15c0e0
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Registration.c
@@ -0,0 +1,72 @@
+/*
+ * 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 <LongBow/unit-test.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 "../cpi_NameRouteProtocolType.c"
+
+
+LONGBOW_TEST_RUNNER(cpi_NameRouteProtocolType)
+{
+ // 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(cpi_NameRouteProtocolType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(cpi_NameRouteProtocolType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
+
+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;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_NameRouteProtocolType);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntry.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntry.c
new file mode 100644
index 00000000..97b85ead
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntry.c
@@ -0,0 +1,547 @@
+/*
+ * 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 <LongBow/unit-test.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../cpi_RouteEntry.c"
+
+LONGBOW_TEST_RUNNER(cpi_RouteEntry)
+{
+ // 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(Getters);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(cpi_RouteEntry)
+{
+ 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(cpi_RouteEntry)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_CreateSymbolic);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_ToJson_1);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_ToJson_2);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_ToJson_3);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_ToJson_4);
+
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_FromJson_1);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_FromJson_2);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_FromJson_3);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_FromJson_4);
+}
+
+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, cpiRouteEntry_Create_Destroy)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ unsigned cost = 4;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost);
+ cpiRouteEntry_Destroy(&route);
+
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance on create/destroy: %u", parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_Copy)
+{
+ CCNxName *prefix_a = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *a = cpiRouteEntry_Create(prefix_a, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ CPIRouteEntry *b = cpiRouteEntry_Copy(a);
+
+ assertTrue(cpiRouteEntry_Equals(a, b), "Copy did not compare as equals");
+ cpiAddress_Destroy(&nexthop);
+ cpiRouteEntry_Destroy(&a);
+ cpiRouteEntry_Destroy(&b);
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_Equals)
+{
+ CCNxName *prefix_a = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ CCNxName *prefix_b = ccnxName_Copy(prefix_a);
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *a = cpiRouteEntry_Create(prefix_a, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ CPIRouteEntry *b = cpiRouteEntry_Create(prefix_b, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+
+ assertTrue(cpiRouteEntry_Equals(a, b), "Equals did not compare correctly");
+
+ cpiRouteEntry_Destroy(&a);
+ cpiRouteEntry_Destroy(&b);
+ cpiAddress_Destroy(&nexthop);
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_CreateSymbolic)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned cost = 4;
+
+ CPIRouteEntry *route = cpiRouteEntry_CreateSymbolic(prefix, "tun0", cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost);
+ cpiRouteEntry_Destroy(&route);
+
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance on create/destroy: %u", parcMemory_Outstanding());
+}
+
+
+/**
+ * Add route with all options
+ */
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_ToJson_1)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform.
+#if defined(__APPLE__)
+ char truth[] = "{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200,\"LIFETIME\":[3600,0]}";
+#elif defined(__linux__)
+ char truth[] = "{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200,\"LIFETIME\":[3600,0]}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+
+ PARCJSON *test_json = cpiRouteEntry_ToJson(route);
+ char *test = parcJSON_ToCompactString(test_json);
+ assertTrue(strcasecmp(truth, test) == 0, "Route json does not match, expected '%s', got '%s'", truth, test);
+ parcMemory_Deallocate((void **) &test);
+
+ cpiRouteEntry_Destroy(&route);
+ cpiAddress_Destroy(&nexthop);
+ parcJSON_Release(&test_json);
+}
+
+/**
+ * Add route without lifeitme
+ */
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_ToJson_2)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform.
+#if defined(__APPLE__)
+ char truth[] = "{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}";
+#elif defined(__linux__)
+ char truth[] = "{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}";
+#else
+ // Case 1033
+ testUnimplemented("Platform not supported");
+ return;
+#endif
+
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost);
+ PARCJSON *test_json = cpiRouteEntry_ToJson(route);
+ char *test = parcJSON_ToCompactString(test_json);
+ assertTrue(strcasecmp(truth, test) == 0, "Route json does not match, expected '%s', got '%s'", truth, test);
+ parcMemory_Deallocate((void **) &test);
+
+ cpiRouteEntry_Destroy(&route);
+ cpiAddress_Destroy(&nexthop);
+ parcJSON_Release(&test_json);
+}
+
+/**
+ * Add route without lifeitme or nexthop
+ */
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_ToJson_3)
+{
+ char truth[] = "{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}";
+
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost);
+
+ PARCJSON *test_json = cpiRouteEntry_ToJson(route);
+ char *test = parcJSON_ToCompactString(test_json);
+ assertTrue(strcasecmp(truth, test) == 0, "Control message json does not match, expected '%s', got '%s'", truth, test);
+ parcMemory_Deallocate((void **) &test);
+
+ cpiRouteEntry_Destroy(&route);
+ parcJSON_Release(&test_json);
+}
+
+/**
+ * Add route with symbolic name
+ */
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_ToJson_4)
+{
+ // The JSON representation depends on the system sockaddr_in format, which
+ // varies platform to platform.
+ char truth[] = "{\"PREFIX\":\"ccnx:/howdie/stranger\",\"SYMBOLIC\":\"tun0\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200,\"LIFETIME\":[3600,0]}";
+
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_CreateSymbolic(prefix, "tun0", cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ cpiRouteEntry_SetInterfaceIndex(route, ifidx);
+
+ PARCJSON *test_json = cpiRouteEntry_ToJson(route);
+ char *test = parcJSON_ToCompactString(test_json);
+ assertTrue(strcasecmp(truth, test) == 0, "Route json does not match, expected '%s', got '%s'", truth, test);
+ parcMemory_Deallocate((void **) &test);
+
+ cpiRouteEntry_Destroy(&route);
+ parcJSON_Release(&test_json);
+}
+
+/**
+ * Add route with all options
+ */
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_FromJson_1)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *route_truth = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+
+ PARCJSON *truth_json = cpiRouteEntry_ToJson(route_truth);
+
+ CPIRouteEntry *route_test = cpiRouteEntry_FromJson(truth_json);
+ assertTrue(cpiRouteEntry_Equals(route_truth, route_test), "FromJson does not match");
+
+
+ cpiRouteEntry_Destroy(&route_truth);
+ cpiRouteEntry_Destroy(&route_test);
+ cpiAddress_Destroy(&nexthop);
+ parcJSON_Release(&truth_json);
+}
+
+/**
+ * Add route without lifeitme
+ */
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_FromJson_2)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ unsigned cost = 200;
+
+ CPIRouteEntry *route_truth = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost);
+
+ PARCJSON *truth_json = cpiRouteEntry_ToJson(route_truth);
+
+ CPIRouteEntry *route_test = cpiRouteEntry_FromJson(truth_json);
+ assertTrue(cpiRouteEntry_Equals(route_truth, route_test), "FromJson does not match");
+
+
+ cpiRouteEntry_Destroy(&route_truth);
+ cpiRouteEntry_Destroy(&route_test);
+ cpiAddress_Destroy(&nexthop);
+ parcJSON_Release(&truth_json);
+}
+
+/**
+ * Add route without lifeitme or nexthop
+ */
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_FromJson_3)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ unsigned cost = 200;
+
+ CPIRouteEntry *route_truth = cpiRouteEntry_Create(prefix, ifidx, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost);
+
+ PARCJSON *truth_json = cpiRouteEntry_ToJson(route_truth);
+
+ CPIRouteEntry *route_test = cpiRouteEntry_FromJson(truth_json);
+ assertTrue(cpiRouteEntry_Equals(route_truth, route_test), "FromJson does not match");
+
+
+ cpiRouteEntry_Destroy(&route_truth);
+ cpiRouteEntry_Destroy(&route_test);
+ parcJSON_Release(&truth_json);
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_FromJson_4)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *route_truth = cpiRouteEntry_CreateSymbolic(prefix, "tun0", cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+ cpiRouteEntry_SetInterfaceIndex(route_truth, ifidx);
+
+ PARCJSON *truth_json = cpiRouteEntry_ToJson(route_truth);
+
+ CPIRouteEntry *route_test = cpiRouteEntry_FromJson(truth_json);
+ assertTrue(cpiRouteEntry_Equals(route_truth, route_test), "FromJson does not match");
+
+ const char *symbolic = cpiRouteEntry_GetSymbolicName(route_test);
+ assertTrue(strcmp(symbolic, "tun0") == 0, "wrong symbolic name expected 'tun0' got '%s'", symbolic);
+
+ cpiRouteEntry_Destroy(&route_truth);
+ cpiRouteEntry_Destroy(&route_test);
+ parcJSON_Release(&truth_json);
+}
+
+
+// ====================================================
+
+LONGBOW_TEST_FIXTURE(Getters)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetCost);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetInterfaceIndex);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetLifetime);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetNexthop);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetPrefix);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetRouteProtocolType);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetRouteType);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetSymbolicName);
+}
+
+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(Global, cpiRouteEntry_GetCost)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+
+ assertTrue(cpiRouteEntry_GetCost(route) == cost, "Got wrong cost, expected %u got %u", cost, cpiRouteEntry_GetCost(route));
+ cpiAddress_Destroy(&nexthop);
+ cpiRouteEntry_Destroy(&route);
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetInterfaceIndex)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+
+ assertTrue(cpiRouteEntry_GetInterfaceIndex(route) == ifidx, "Got wrong cost, expected %u got %u", ifidx, cpiRouteEntry_GetInterfaceIndex(route));
+ cpiAddress_Destroy(&nexthop);
+ cpiRouteEntry_Destroy(&route);
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetLifetime)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+
+ struct timeval test_time = cpiRouteEntry_GetLifetime(route);
+
+ assertTrue(lifetime.tv_sec == test_time.tv_sec && lifetime.tv_usec == test_time.tv_usec,
+ "Got wrong lifetime, expected %.6f got %.6f",
+ lifetime.tv_sec + 1E-6 * lifetime.tv_usec,
+ test_time.tv_sec + 1E-6 * test_time.tv_usec);
+ cpiAddress_Destroy(&nexthop);
+ cpiRouteEntry_Destroy(&route);
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetNexthop)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+
+ const CPIAddress *test = cpiRouteEntry_GetNexthop(route);
+
+ assertTrue(cpiAddress_Equals(nexthop, test),
+ "Got wrong nexthop, expected %s got %s",
+ cpiAddress_ToString(nexthop),
+ cpiAddress_ToString(test));
+
+ cpiAddress_Destroy(&nexthop);
+ cpiRouteEntry_Destroy(&route);
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetPrefix)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+
+ const CCNxName *test_prefix = cpiRouteEntry_GetPrefix(route);
+
+ assertTrue(ccnxName_Equals(prefix, test_prefix),
+ "Got wrong name, expected %s got %s",
+ ccnxName_ToString(prefix),
+ ccnxName_ToString(test_prefix));
+
+ cpiAddress_Destroy(&nexthop);
+ cpiRouteEntry_Destroy(&route);
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetRouteProtocolType)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+
+ assertTrue(cpiRouteEntry_GetRouteProtocolType(route) == cpiNameRouteProtocolType_STATIC,
+ "Got wrong protocol, expected %d got %d",
+ cpiNameRouteProtocolType_STATIC,
+ cpiRouteEntry_GetRouteProtocolType(route));
+
+ cpiAddress_Destroy(&nexthop);
+ cpiRouteEntry_Destroy(&route);
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetRouteType)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ unsigned ifidx = 55;
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+
+ assertTrue(cpiRouteEntry_GetRouteType(route) == cpiNameRouteType_LONGEST_MATCH,
+ "Got wrong route type, expected %d got %d",
+ cpiNameRouteType_LONGEST_MATCH,
+ cpiRouteEntry_GetRouteType(route));
+
+ cpiAddress_Destroy(&nexthop);
+ cpiRouteEntry_Destroy(&route);
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetSymbolicName)
+{
+ CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger");
+ CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 });
+ struct timeval lifetime = { 3600, 0 };
+ unsigned cost = 200;
+ const char *symbolicName = "tun0";
+
+ CPIRouteEntry *route = cpiRouteEntry_CreateSymbolic(prefix, symbolicName, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost);
+
+ const char *test = cpiRouteEntry_GetSymbolicName(route);
+
+ assertTrue(strcmp(symbolicName, test) == 0, "Got wrong symbolic name, expected %s got %s", symbolicName, test);
+ cpiAddress_Destroy(&nexthop);
+ cpiRouteEntry_Destroy(&route);
+}
+
+// =============================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_RouteEntry);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntryList.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntryList.c
new file mode 100644
index 00000000..94f2b473
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntryList.c
@@ -0,0 +1,177 @@
+/*
+ * 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 "../cpi_RouteEntryList.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(cpi_RouteEntryList)
+{
+ // 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(cpi_RouteEntryList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(cpi_RouteEntryList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntryList_Append);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntryList_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntryList_FromJson);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntryList_FromJson_EmptyList);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntryList_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntryList_ToJson);
+}
+
+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, cpiRouteEntryList_Append)
+{
+ CPIRouteEntryList *list = cpiRouteEntryList_Create();
+
+ CPIRouteEntry *entry = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1);
+ cpiRouteEntryList_Append(list, entry);
+
+ assertTrue(parcArrayList_Size(list->listOfRouteEntries) == 1, "got wrong size, expected %u got %zu", 1, parcArrayList_Size(list->listOfRouteEntries));
+
+ cpiRouteEntryList_Destroy(&list);
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntryList_Create_Destroy)
+{
+ CPIRouteEntryList *list = cpiRouteEntryList_Create();
+ cpiRouteEntryList_Destroy(&list);
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after create/destroy");
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntryList_FromJson)
+{
+ char truth_string[] = "{\"Routes\":[{\"PREFIX\":\"ccnx:/hello\",\"INTERFACE\":1,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":1}]}";
+
+ CPIRouteEntryList *truth_list = cpiRouteEntryList_Create();
+ CPIRouteEntry *entry = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1);
+ cpiRouteEntryList_Append(truth_list, entry);
+
+ PARCJSON *truth_json = parcJSON_ParseString(truth_string);
+ CPIRouteEntryList *test_list = cpiRouteEntryList_FromJson(truth_json);
+
+ assertTrue(cpiRouteEntryList_Equals(truth_list, test_list), "Lists do not match");
+
+ cpiRouteEntryList_Destroy(&test_list);
+ parcJSON_Release(&truth_json);
+ cpiRouteEntryList_Destroy(&truth_list);
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntryList_FromJson_EmptyList)
+{
+ char truth_string[] = "{\"Routes\":[]}";
+
+ CPIRouteEntryList *truth_list = cpiRouteEntryList_Create();
+
+ PARCJSON *truth_json = parcJSON_ParseString(truth_string);
+ CPIRouteEntryList *test_list = cpiRouteEntryList_FromJson(truth_json);
+
+ assertTrue(cpiRouteEntryList_Equals(truth_list, test_list), "Lists do not match");
+
+ cpiRouteEntryList_Destroy(&test_list);
+ parcJSON_Release(&truth_json);
+ cpiRouteEntryList_Destroy(&truth_list);
+}
+
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntryList_Equals)
+{
+ CPIRouteEntryList *list_a = cpiRouteEntryList_Create();
+ CPIRouteEntry *entry_a = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1);
+ cpiRouteEntryList_Append(list_a, entry_a);
+
+ CPIRouteEntryList *list_b = cpiRouteEntryList_Create();
+ CPIRouteEntry *entry_b = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1);
+ cpiRouteEntryList_Append(list_b, entry_b);
+
+ CPIRouteEntryList *list_c = cpiRouteEntryList_Create();
+ CPIRouteEntry *entry_c = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1);
+ cpiRouteEntryList_Append(list_c, entry_c);
+
+ CPIRouteEntryList *unequal_length = cpiRouteEntryList_Create();
+ CPIRouteEntry *entry_d = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1);
+ CPIRouteEntry *entry_e = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1);
+ cpiRouteEntryList_Append(unequal_length, entry_d);
+ cpiRouteEntryList_Append(unequal_length, entry_e);
+
+ CPIRouteEntryList *unequal_value = cpiRouteEntryList_Create();
+ CPIRouteEntry *entry_f = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 2, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1);
+ cpiRouteEntryList_Append(unequal_value, entry_f);
+
+ assertEqualsContract(cpiRouteEntryList_Equals, list_a, list_b, list_c, unequal_length, unequal_value);
+
+ cpiRouteEntryList_Destroy(&unequal_value);
+ cpiRouteEntryList_Destroy(&unequal_length);
+
+ cpiRouteEntryList_Destroy(&list_a);
+ cpiRouteEntryList_Destroy(&list_b);
+ cpiRouteEntryList_Destroy(&list_c);
+}
+
+LONGBOW_TEST_CASE(Global, cpiRouteEntryList_ToJson)
+{
+ char truth_string[] = "{\"Routes\":[{\"PREFIX\":\"ccnx:/hello\",\"INTERFACE\":1,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":1}]}";
+
+ CPIRouteEntryList *list = cpiRouteEntryList_Create();
+
+ CPIRouteEntry *entry = cpiRouteEntry_Create(ccnxName_CreateFromCString("lci:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1);
+ cpiRouteEntryList_Append(list, entry);
+
+ PARCJSON *json = cpiRouteEntryList_ToJson(list);
+ char *test = parcJSON_ToCompactString(json);
+ assertTrue(strcmp(truth_string, test) == 0, "Got wrong JSON.\nexpected: %s\ngot %s\n", truth_string, test);
+ parcMemory_Deallocate((void **) &test);
+
+ parcJSON_Release(&json);
+ cpiRouteEntryList_Destroy(&list);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_RouteEntryList);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/api/notify/CMakeLists.txt b/libccnx-transport-rta/ccnx/api/notify/CMakeLists.txt
new file mode 100644
index 00000000..d22e4db3
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/notify/CMakeLists.txt
@@ -0,0 +1,39 @@
+# Define a few configuration variables that we want accessible in the software
+
+set(CCNX_API_NOTIFY_HEADERS
+ ccnxNotifyAPI_About.h
+ notify_Status.h
+ notify_Timer.h
+)
+
+set(CCNX_API_NOTIFY_SOURCE_FILES
+ ccnxNotifyAPI_About.c
+ notify_Status.c
+)
+
+
+add_library(ccnx_api_notify STATIC ${CCNX_API_NOTIFY_SOURCE_FILES} ${CCNX_API_NOTIFY_HEADERS})
+add_library(ccnx_api_notify.shared SHARED ${CCNX_API_NOTIFY_SOURCE_FILES})
+
+source_group(Sources FILES ${CCNX_API_NOTIFY_SOURCE_FILES})
+source_group(Sources FILES ${CCNX_API_NOTIFY_HEADERS})
+
+set_target_properties(ccnx_api_notify.shared PROPERTIES
+ C_STANDARD 99
+ SOVERSION 1
+ VERSION 1.0
+ OUTPUT_NAME ccnx_api_notify )
+
+set(libccnx_api_notify_libraries
+ ccnx_api_notify
+ ccnx_api_notify.shared
+ )
+
+foreach(lib ${libccnx_api_notify_libraries})
+ install(TARGETS ${lib} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
+ set_property(TARGET ${lib} PROPERTY C_STANDARD 99)
+endforeach()
+
+install(FILES ${CCNX_API_NOTIFY_HEADERS} DESTINATION include/ccnx/api/notify )
+
+#add_subdirectory(test)
diff --git a/libccnx-transport-rta/ccnx/api/notify/README b/libccnx-transport-rta/ccnx/api/notify/README
new file mode 100644
index 00000000..a2eb8879
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/notify/README
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+
+API to handle notifications from the Transport. These notifications
+are specific to the RTA Transport, in that they use the Component
+model and Component names.
+
diff --git a/libccnx-transport-rta/ccnx/api/notify/ccnxNotifyAPI_About.c b/libccnx-transport-rta/ccnx/api/notify/ccnxNotifyAPI_About.c
new file mode 100644
index 00000000..25772c22
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/notify/ccnxNotifyAPI_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T09:29:05Z
+
+#include "ccnxNotifyAPI_About.h"
+
+const char *ccnxNotifyAPI_What = "@(#)" "ccnxNotifyAPI " RELEASE_VERSION " 2017-02-20T14:20:21.238467"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+ccnxNotifyAPIAbout_Name(void)
+{
+ return "ccnxNotifyAPI";
+}
+
+const char *
+ccnxNotifyAPIAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+ccnxNotifyAPIAbout_About(void)
+{
+ return "ccnxNotifyAPI "RELEASE_VERSION " 2017-02-20T14:20:21.238467" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxNotifyAPIAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxNotifyAPIAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+ccnxNotifyAPIAbout_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-transport-rta/ccnx/api/notify/ccnxNotifyAPI_About.h b/libccnx-transport-rta/ccnx/api/notify/ccnxNotifyAPI_About.h
new file mode 100644
index 00000000..07d9ff50
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/notify/ccnxNotifyAPI_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T09:29:05Z
+
+#ifndef ccnxNotifyAPI_About_h
+#define ccnxNotifyAPI_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *ccnxNotifyAPI_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *ccnxNotifyAPIAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *ccnxNotifyAPIAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *ccnxNotifyAPIAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *ccnxNotifyAPIAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *ccnxNotifyAPIAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *ccnxNotifyAPIAbout_LongNotice(void);
+
+#endif // ccnxNotifyAPI_About_h
diff --git a/libccnx-transport-rta/ccnx/api/notify/notify_Status.c b/libccnx-transport-rta/ccnx/api/notify/notify_Status.c
new file mode 100644
index 00000000..25ade9fb
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/notify/notify_Status.c
@@ -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.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_JSON.h>
+
+#include <ccnx/api/notify/notify_Status.h>
+
+// These string constants are used in the JSON configuration
+
+static const char jsonNotifyStatus[] = "notifyStatus";
+static const char param_CONNECTION[] = "connectionId";
+static const char param_CODE[] = "statusCode";
+static const char param_NAME[] = "name";
+static const char param_MESSAGE[] = "message";
+
+struct notify_status {
+ int apiFd;
+ NotifyStatusCode code;
+ CCNxName *name;
+ char *message;
+};
+
+static void
+_notifyStatus_Destroy(NotifyStatus **notifyStatusPtr)
+{
+ NotifyStatus *status = *notifyStatusPtr;
+ if (status->name) {
+ ccnxName_Release(&status->name);
+ }
+ if (status->message) {
+ parcMemory_Deallocate((void **) &status->message);
+ }
+}
+
+parcObject_ExtendPARCObject(NotifyStatus, _notifyStatus_Destroy, NULL, NULL, notifyStatus_Equals, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(notifyStatus, NotifyStatus);
+
+parcObject_ImplementRelease(notifyStatus, NotifyStatus);
+
+NotifyStatus *
+notifyStatus_Create(int apiFd, NotifyStatusCode code, CCNxName *name, const char *message)
+{
+ NotifyStatus *result = parcObject_CreateInstance(NotifyStatus);
+ result->apiFd = apiFd;
+ result->code = code;
+ result->name = name == NULL ? NULL : ccnxName_Acquire(name);
+ result->message = message == NULL ? NULL : parcMemory_StringDuplicate(message, strlen(message));
+
+ return result;
+}
+
+static bool
+_StringEquals(const char *x, const char *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+ return strcmp(x, y) == 0;
+}
+
+bool
+notifyStatus_Equals(const NotifyStatus *x, const NotifyStatus *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ if (x->apiFd == y->apiFd) {
+ if (x->code == y->code) {
+ if (_StringEquals(x->message, y->message)) {
+ if (ccnxName_Equals(x->name, y->name)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+int
+notifyStatus_GetFiledes(const NotifyStatus *status)
+{
+ return status->apiFd;
+}
+
+NotifyStatusCode
+notifyStatus_GetStatusCode(const NotifyStatus *status)
+{
+ return status->code;
+}
+
+CCNxName *
+notifyStatus_GetName(const NotifyStatus *status)
+{
+ return status->name;
+}
+
+char *
+notifyStatus_GetMessage(const NotifyStatus *status)
+{
+ return status->message;
+}
+
+void
+notifyStatus_Display(const NotifyStatus *status, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "NotifyStatus%p { .apiFd=%d, .code=%d ", status, status->apiFd, status->code);
+ ccnxName_Display(status->name, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, ".message=\"%s\"\n", status->message);
+}
+
+bool
+notifyStatus_IsConnectionOpen(const NotifyStatus *status)
+{
+ return status->code == notifyStatusCode_CONNECTION_OPEN;
+}
+
+bool
+notifyStatus_IsFlowControlStarted(const NotifyStatus *status)
+{
+ return status->code == notifyStatusCode_FLOW_CONTROL_STARTED;
+}
+
+NotifyStatus *
+notifyStatus_ParseJSON(const PARCJSON *json)
+{
+ NotifyStatus *result = NULL;
+
+ PARCJSONValue *status = parcJSON_GetValueByName(json, jsonNotifyStatus);
+ if (status != NULL) {
+ PARCJSON *status_json = parcJSONValue_GetJSON(status);
+ int apiFd = (int) parcJSONValue_GetInteger(parcJSON_GetValueByName(status_json, param_CONNECTION));
+ NotifyStatusCode code =
+ (NotifyStatusCode) parcJSONValue_GetInteger(parcJSON_GetValueByName(status_json, param_CODE));
+
+ CCNxName *name = NULL;
+
+ PARCJSONValue *nameValue = parcJSON_GetValueByName(status_json, param_NAME);
+ if (nameValue != NULL) {
+ PARCBuffer *sBuf = parcJSONValue_GetString(nameValue);
+ const char *p = parcBuffer_Overlay(sBuf, 0);
+ if (p != NULL) {
+ name = ccnxName_CreateFromCString(p);
+ }
+ }
+
+ const char *message = NULL;
+ PARCJSONValue *messageValue = parcJSON_GetValueByName(status_json, param_MESSAGE);
+ if (messageValue != NULL) {
+ PARCBuffer *sBuf = parcJSONValue_GetString(messageValue);
+ message = parcBuffer_Overlay(sBuf, 0);
+ }
+
+ result = notifyStatus_Create(apiFd, code, name, message);
+ if (name != NULL) {
+ ccnxName_Release(&name);
+ }
+ }
+ return result;
+}
+
+PARCJSON *
+notifyStatus_ToJSON(const NotifyStatus *status)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ parcJSON_AddInteger(json, param_CONNECTION, notifyStatus_GetFiledes(status));
+ parcJSON_AddInteger(json, param_CODE, notifyStatus_GetStatusCode(status));
+
+ if (notifyStatus_GetName(status) != NULL) {
+ char *nameAsString = ccnxName_ToString(notifyStatus_GetName(status));
+ parcJSON_AddString(json, param_NAME, nameAsString);
+ parcMemory_Deallocate((void **) &nameAsString);
+ }
+ if (notifyStatus_GetMessage(status) != NULL) {
+ parcJSON_AddString(json, param_MESSAGE, notifyStatus_GetMessage(status));
+ }
+
+ PARCJSON *result = parcJSON_Create();
+ parcJSON_AddObject(result, jsonNotifyStatus, json);
+ parcJSON_Release(&json);
+
+ return result;
+}
diff --git a/libccnx-transport-rta/ccnx/api/notify/notify_Status.h b/libccnx-transport-rta/ccnx/api/notify/notify_Status.h
new file mode 100644
index 00000000..3fcdcb1d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/notify/notify_Status.h
@@ -0,0 +1,345 @@
+/*
+ * 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 notify_Status.h
+ *
+ * @brief
+ * An API to handle notifications from the Transport.
+ *
+ * These notifications are specific to the RTA Transport, in that they use the Component model and Component names.
+ *
+ */
+#ifndef Libccnx_notifyStatus_h
+#define Libccnx_notifyStatus_h
+
+#include <parc/algol/parc_JSON.h>
+#include <ccnx/common/ccnx_Name.h>
+
+struct notify_status;
+/**
+ * @typedef NotifyStatus
+ * @brief Notifications from Transport
+ */
+typedef struct notify_status NotifyStatus;
+
+// This needs to be replaced with a more sophisticated encoding scheme that individual stack components can use. Case 1035
+/**
+ * @typedef NotifyStatusCode
+ * @brief Codes for Notify Status
+ */
+typedef enum {
+ // TRANSPORT_READY = 1, // returned when Transport_Create finished
+ // TRANSPORT_DESTROYED = 2, // when Transport_Destroy is done
+ notifyStatusCode_OPEN_ERROR = 3, // error when opening a connection stack
+ notifyStatusCode_CONNECTION_OPEN = 4, // returned when a connection is opened
+ notifyStatusCode_CONNECTION_CLOSED = 5, // returned when close is finished
+ notifyStatusCode_FORWARDER_NOT_AVAILABLE = 6, // connection problem with forwarder
+ notifyStatusCode_FLOW_CONTROL_STARTED = 7, // when flow control starts on a name
+ notifyStatusCode_FLOW_CONTROL_FINISHED = 8, // after final block is passed up
+ notifyStatusCode_FLOW_CONTROL_ERROR = 9, // some hard error on the name
+ notifyStatusCode_ENCODING_ERROR = 10, // something bad in the codec
+ notifyStatusCode_SIGNING_ERROR = 11, // error signing
+ notifyStatusCode_SEND_ERROR = 12, // some other "down" stack error
+} NotifyStatusCode;
+
+/**
+ * @typedef NotifyStatusDirection
+ * @brief The direction of the NotifyStatus
+ */
+typedef enum {
+ notifyStatusDirection_UPSTACK,
+ notifyStatusDirection_DOWNSTACK
+} NotifyStatusDirection;
+
+/**
+ * Create an instance of `NotifyStatus`.
+ *
+ * @param [in] apiFd The corresponding api file descriptor.
+ * @param [in] code The NotifyStatusCode for this status.
+ * @param [in] name An associated CCNxName
+ * @param [in] message An (optional) string message
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a valid NotifyStatus instance that must be released via notifyStatus_Release().
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/a/b/c");
+ * NotifyStatus *expected = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ * }
+ * @endcode
+ *
+ * @see {@link notifyStatus_Release}
+ */
+NotifyStatus *notifyStatus_Create(int apiFd, NotifyStatusCode code, CCNxName *name, const char *message);
+
+/**
+ * Increase the number of references to a `NotifyStatus`.
+ *
+ * Note that new `NotifyStatus` is not created,
+ * only that the given `NotifyStatus` reference count is incremented.
+ * Discard the reference by invoking {@link notifyStatus_Release}.
+ *
+ * @param [in] status A pointer to a `NotifyStatus` instance.
+ * @return The input `NotifyStatus` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/a/b/c");
+ * NotifyStatus *status = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ *
+ * NotifyStatus *x_2 = notifyStatus_Acquire(status);
+ *
+ * notifyStatus_Release(&status);
+ * notifyStatus_Release(&x_2);
+ * }
+ * @endcode
+ */
+NotifyStatus *notifyStatus_Acquire(const NotifyStatus *status);
+
+/**
+ * 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] statusPtr A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/a/b/c");
+ * NotifyStatus *status = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ *
+ * notifyStatus_Release(&status);
+ * }
+ * @endcode
+ */
+void notifyStatus_Release(NotifyStatus **statusPtr);
+
+/**
+ * Returns true if contents of two NotifyStatus objects are the same.
+ *
+ * @param [in] x object 1
+ * @param [in] y object 2
+ *
+ * @return true X & Y are equal
+ * @return false X & Y are not equal
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/a/b/c");
+ * NotifyStatus *status1 = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ * NotifyStatus *status2 = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ *
+ * if (notifyStatus_Equals(status1, status2)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+bool notifyStatus_Equals(const NotifyStatus *x, const NotifyStatus *y);
+
+/**
+ * Print a human readable representation of the given `NotifyStatus`.
+ *
+ * @param [in] status 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:/a/b/c");
+ * NotifyStatus *status = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ *
+ * notifyStatus_Display(status, 0);
+ *
+ * notifyStatus_Release(&status);
+ * }
+ * @endcode
+ */
+void notifyStatus_Display(const NotifyStatus *status, int indentation);
+
+/**
+ * Get the associated file descriptor of the given `NotifyStatus` instance.
+ *
+ * @param [in] status A pointer to a valid instance of `NotifyStatus`.
+ *
+ * @return The associated file descriptor of this NotifyStatus instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/a/b/c");
+ * NotifyStatus *status = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ *
+ * int fd = notifyStatus_GetFiledes(status);
+ * }
+ * @endcode
+ */
+int notifyStatus_GetFiledes(const NotifyStatus *status);
+
+/**
+ * Get the associated {@link NotifyStatusCode} of the given `NotifyStatus` instance.
+ *
+ * @param [in] status A pointer to a valid instance of `NotifyStatus`.
+ *
+ * @return The associated NotifyStatusCode of the given `NotifyStatus` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/a/b/c");
+ * NotifyStatus *status = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ *
+ * NotifyStatusCode code = notifyStatus_GetStatusCode(status);
+ * }
+ * @endcode
+ */
+NotifyStatusCode notifyStatus_GetStatusCode(const NotifyStatus *status);
+
+/**
+ * Get the associated {@link CCNxName} of the given `NotifyStatus` instance.
+ *
+ * @param [in] status A pointer to a valid instance of `NotifyStatus`.
+ *
+ * @return The `CCNxName` of this `NotifyStatus` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/a/b/c");
+ * NotifyStatus *status = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ *
+ * NotifyStatusCode code = notifyStatus_GetStatusCode(status);
+ * }
+ * @endcode
+ */
+CCNxName *notifyStatus_GetName(const NotifyStatus *status);
+
+/**
+ * Get the associated {@link CCNxName} of the given `NotifyStatus` instance.
+ *
+ * @param [in] status A pointer to a valid instance of `NotifyStatus`.
+ *
+ * @return The message of this NotifyStatus instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/a/b/c");
+ * NotifyStatus *status = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ *
+ * NotifyStatusCode code = notifyStatus_GetStatusCode(status);
+ * }
+ * @endcode
+ */
+char *notifyStatus_GetMessage(const NotifyStatus *status);
+
+/**
+ * Return a {@link PARCJSON} representation of the given `NotifyStatus` instance.
+ *
+ * @param [in] status A pointer to a valid instance of `NotifyStatus`.
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a valid `PARCJSON` instance
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/a/b/c");
+ * NotifyStatus *status = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ *
+ * PARCJSON *json = notifyStatus_ToJSON(status);
+ * }
+ * @endcode
+ */
+PARCJSON *notifyStatus_ToJSON(const NotifyStatus *status);
+
+/**
+ * Create a new `NotifyStatus` instance from a {@link PARCJSON} instance.
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a valid `NotifyStatus` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/a/b/c");
+ * NotifyStatus *status = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ *
+ * PARCJSON *json = notifyStatus_ToJSON(status);
+ *
+ * NotifyStatus *status2 = notifyStatus_ParseJSON(json)
+ * }
+ * @endcode
+ */
+NotifyStatus *notifyStatus_ParseJSON(const PARCJSON *json);
+
+/**
+ * Evaluate to `true` if the given `NotifyStatus` indicates a Connection Open.
+ *
+ * @param [in] status A pointer to a `NotifyStatus` instance.
+ *
+ * @return `true` The given `NotifyStatus` indicates a Connection open.
+ * @return `false` The given ``NotifyStatus` indicates that the Connection is not open.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/a/b/c");
+ * NotifyStatus *status = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ *
+ * if (notifyStatus_IsConnectionOpen(status)) {
+ * printf("Connection is open\n");
+ * }
+ * }
+ * @endcode
+ */
+bool notifyStatus_IsConnectionOpen(const NotifyStatus *status);
+
+/**
+ * Return `true` if the given status indicates that the flow control has started.
+ *
+ * @param [in] status A pointer to a NotifyStatus instance.
+ *
+ * @return `true` The given `NotifyStatu`s indicates that flow controller has started
+ * @return `false` The given `NotifyStatus` indicates that the flow controller has not started.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxName *name = ccnxName_CreateFromCString("lci:/a/b/c");
+ * NotifyStatus *status = notifyStatus_Create(1, notifyStatus_CONNECTION_OPEN, name, "Good to go");
+ *
+ * if (notifyStatus_IsFlowControlStarted(status)) {
+ * printf("Flow controller has started\n");
+ * }
+ * }
+ * @endcode
+ */
+bool notifyStatus_IsFlowControlStarted(const NotifyStatus *status);
+#endif // Libccnx_notifyStatus_h
diff --git a/libccnx-transport-rta/ccnx/api/notify/notify_Timer.h b/libccnx-transport-rta/ccnx/api/notify/notify_Timer.h
new file mode 100644
index 00000000..179d57ba
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/notify/notify_Timer.h
@@ -0,0 +1,18 @@
+/*
+ * 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_notify_Timer_h
+#define Libccnx_notify_Timer_h
+#endif // Libccnx_notify_Timer_h
diff --git a/libccnx-transport-rta/ccnx/api/notify/test/.gitignore b/libccnx-transport-rta/ccnx/api/notify/test/.gitignore
new file mode 100644
index 00000000..64e67423
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/notify/test/.gitignore
@@ -0,0 +1 @@
+test_notify_Status
diff --git a/libccnx-transport-rta/ccnx/api/notify/test/CMakeLists.txt b/libccnx-transport-rta/ccnx/api/notify/test/CMakeLists.txt
new file mode 100644
index 00000000..97b14602
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/notify/test/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_notify_Status
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-transport-rta/ccnx/api/notify/test/test_notify_Status.c b/libccnx-transport-rta/ccnx/api/notify/test/test_notify_Status.c
new file mode 100644
index 00000000..04269b0a
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/notify/test/test_notify_Status.c
@@ -0,0 +1,96 @@
+/*
+ * 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 "../notify_Status.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(notify_Status)
+{
+ // 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(notify_Status)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(notify_Status)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, notifyStatus_ToJSON);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, notifyStatus_ToJSON)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/a/b/c");
+ NotifyStatus *expected = notifyStatus_Create(1, notifyStatusCode_CONNECTION_OPEN, name, "foo");
+
+ PARCJSON *json = notifyStatus_ToJSON(expected);
+
+ NotifyStatus *actual = notifyStatus_ParseJSON(json);
+
+ assertTrue(notifyStatus_Equals(expected, actual), "Failed to create and parse NotifyStatus")
+ {
+ notifyStatus_Display(expected, 0);
+ notifyStatus_Display(actual, 0);
+ }
+}
+
+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(notify_Status);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/config.h.in b/libccnx-transport-rta/ccnx/config.h.in
new file mode 100644
index 00000000..5d047cfc
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/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-transport-rta/ccnx/transport/.gitignore b/libccnx-transport-rta/ccnx/transport/.gitignore
new file mode 100644
index 00000000..1f13e4f3
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/.gitignore
@@ -0,0 +1,35 @@
+*.lo
+*.la
+*.pc
+bin/
+lib/
+include/
+Libevent/test/
+Libevent/sample/
+Libevent/.deps/
+Libevent/.libs/
+Libevent/Makefile
+Libevent/config.h
+Libevent/config.log
+Libevent/config.status
+Libevent/libtool
+Libevent/stamp-h1
+
+transport_rta/tlv_1.0/test/test_tlv_DecoderParsers
+transport_rta/tlv_1.0/test/test_tlv_Encoder
+transport_rta/tlv_1.0/test/test_tlv_EncoderCodecs
+transport_rta/test/test_component_Codec_Tlv
+
+transport_rta/core/test/test_rta_ComponentStats
+transport_rta/connectors/test/test_rta_ApiConnection
+
+transport_rta/components/test/test_codec_Signing
+transport_rta/components/test/test_component_Codec_Null
+transport_rta/components/test/test_component_Flowcontrol_Null
+transport_rta/components/test/test_component_Testing
+transport_rta/components/test/test_component_Verifier_Enumerated
+transport_rta/components/test/test_component_Verifier_Locator
+transport_rta/components/test/test_component_Verifier_Null
+
+transport_rta/components/Flowcontrol_Vegas/test/test_component_Vegas
+transport_rta/components/Flowcontrol_Vegas/test/test_vegas_Session
diff --git a/libccnx-transport-rta/ccnx/transport/CMakeLists.txt b/libccnx-transport-rta/ccnx/transport/CMakeLists.txt
new file mode 100644
index 00000000..076b637a
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/CMakeLists.txt
@@ -0,0 +1,216 @@
+set(BASE_HDRS
+ librta_About.h
+ )
+
+set(COMMON_HDRS
+ common/transport.h
+ common/ccnx_TransportConfig.h
+ common/transport_Message.h
+ common/transport_MetaMessage.h
+ common/ccnx_StackConfig.h
+ common/ccnx_ConnectionConfig.h
+ )
+
+source_group(common FILES ${COMMON_HDRS})
+
+set(RTA_CORE_HDRS
+ transport_rta/rta_Transport.h
+ transport_rta/core/components.h
+ transport_rta/core/rta.h
+ transport_rta/core/rta_ComponentQueue.h
+ transport_rta/core/rta_ComponentStats.h
+ transport_rta/core/rta_Connection.h
+ transport_rta/core/rta_ConnectionTable.h
+ transport_rta/core/rta_Framework.h
+ transport_rta/core/rta_Framework_Commands.h
+ transport_rta/core/rta_Framework_NonThreaded.h
+ transport_rta/core/rta_Framework_Services.h
+ transport_rta/core/rta_Framework_Threaded.h
+ transport_rta/core/rta_Framework_private.h
+ transport_rta/core/rta_Logger.h
+ transport_rta/core/rta_ProtocolStack.h
+ test_tools/bent_pipe.h
+ test_tools/traffic_tools.h
+ )
+
+source_group(core FILES ${RTA_CORE_HDRS})
+
+set(TEST_TOOLS_HDRS
+ test_tools/bent_pipe.h
+ test_tools/traffic_tools.h
+ )
+
+set(RTA_COMMANDS_HDRS
+ transport_rta/commands/rta_CommandCloseConnection.h
+ transport_rta/commands/rta_CommandCreateProtocolStack.h
+ transport_rta/commands/rta_CommandDestroyProtocolStack.h
+ transport_rta/commands/rta_Command.h
+ transport_rta/commands/rta_CommandOpenConnection.h
+ transport_rta/commands/rta_CommandTransmitStatistics.h
+ )
+
+source_group(rta_commands FILES ${RTA_COMMANDS_HDRS})
+
+set(RTA_CONFIG_HDRS
+ transport_rta/config/config_ApiConnector.h
+ transport_rta/config/config_Codec_Tlv.h
+ transport_rta/config/config_CryptoCache.h
+ transport_rta/config/config_FlowControl_Vegas.h
+ transport_rta/config/config_Forwarder_Local.h
+ transport_rta/config/config_Forwarder_Metis.h
+ transport_rta/config/config_InMemoryVerifier.h
+ transport_rta/config/config_ProtocolStack.h
+ transport_rta/config/config_PublicKeySigner.h
+ transport_rta/config/config_Signer.h
+ transport_rta/config/config_SymmetricKeySigner.h
+ transport_rta/config/config_TestingComponent.h
+ )
+
+source_group(rta_config FILES ${RTA_CONFIG_HDRS})
+
+set(RTA_CONNECTORS_HDRS
+ transport_rta/connectors/connector_Api.h
+ transport_rta/connectors/rta_ApiConnection.h
+ transport_rta/connectors/connector_Forwarder.h
+ )
+
+source_group(rta_connectors FILES ${RTA_CONNECTORS_HDRS})
+
+set(RTA_COMPONENTS_HDRS
+ transport_rta/components/Flowcontrol_Vegas/vegas_private.h
+ transport_rta/components/codec_Signing.h
+ transport_rta/components/component_Codec.h
+ transport_rta/components/component_Flowcontrol.h
+ transport_rta/components/component_Testing.h
+ )
+
+source_group(rta_components FILES ${RTA_COMPONENTS_HDRS})
+
+set(COMMON_SRCS
+ librta_About.c
+ common/transport.c
+ common/ccnx_TransportConfig.c
+ common/transport_Message.c
+ common/transport_MetaMessage.c
+ common/ccnx_StackConfig.c
+ common/ccnx_ConnectionConfig.c
+ )
+
+source_group(common FILES ${COMMON_SRCS})
+
+set(RTA_CORE_SRCS
+ transport_rta/core/rta_ComponentStats.c
+ transport_rta/core/rta_Component.c
+ transport_rta/core/rta_Connection.c
+ transport_rta/core/rta_ConnectionTable.c
+ transport_rta/core/rta_Framework.c
+ transport_rta/core/rta_Framework_Commands.c
+ transport_rta/core/rta_Framework_Services.c
+ transport_rta/core/rta_Framework_Threaded.c
+ transport_rta/core/rta_Framework_NonThreaded.c
+ transport_rta/core/rta_Logger.c
+ transport_rta/core/rta_ProtocolStack.c
+ transport_rta/rta_Transport.c
+ test_tools/bent_pipe.c
+ test_tools/traffic_tools.c
+ )
+
+source_group(core FILES ${RTA_CORE_SRCS})
+
+set(RTA_COMMANDS_SRCS
+ transport_rta/commands/rta_Command.c
+ transport_rta/commands/rta_CommandCloseConnection.c
+ transport_rta/commands/rta_CommandCreateProtocolStack.c
+ transport_rta/commands/rta_CommandDestroyProtocolStack.c
+ transport_rta/commands/rta_CommandOpenConnection.c
+ transport_rta/commands/rta_CommandTransmitStatistics.c
+ )
+
+source_group(rta_commands FILES ${RTA_COMMANDS_SRCS})
+
+set(RTA_CONFIG_SRCS
+ transport_rta/config/config_ApiConnector.c
+ transport_rta/config/config_Codec_Tlv.c
+ transport_rta/config/config_FlowControl_Vegas.c
+ transport_rta/config/config_Forwarder_Local.c
+ transport_rta/config/config_Forwarder_Metis.c
+ transport_rta/config/config_TestingComponent.c
+ transport_rta/config/config_InMemoryVerifier.c
+ transport_rta/config/config_ProtocolStack.c
+ transport_rta/config/config_PublicKeySigner.c
+ transport_rta/config/config_Signer.c
+ transport_rta/config/config_SymmetricKeySigner.c
+ )
+
+source_group(rta_config FILES ${RTA_CONFIG_SRCS})
+
+set(RTA_CONNECTORS_SRCS
+ transport_rta/connectors/connector_Api.c
+ transport_rta/connectors/rta_ApiConnection.c
+ transport_rta/connectors/connector_Forwarder_Local.c
+ transport_rta/connectors/connector_Forwarder_Metis.c
+ )
+
+source_group(rta_connectors FILES ${RTA_CONNECTORS_SRCS})
+
+set(RTA_COMPONENTS_SRCS
+ transport_rta/components/codec_Signing.c
+ transport_rta/components/component_Codec_Tlv.c
+ transport_rta/components/Flowcontrol_Vegas/component_Vegas.c
+ transport_rta/components/Flowcontrol_Vegas/vegas_Session.c
+ transport_rta/components/component_Testing.c
+ )
+
+source_group(rta_components FILES ${RTA_COMPONENTS_SRCS})
+
+set(TRANSPORT_RTA_SOURCE_FILES
+ ${BASE_HDRS}
+ ${COMMON_HDRS}
+ ${RTA_CORE_HDRS}
+ ${RTA_CONFIG_HDRS}
+ ${RTA_COMPONENTS_HDRS}
+ ${RTA_CONNECTORS_HDRS}
+ ${RTA_COMMANDS_HDRS}
+ ${TEST_TOOLS_HDRS}
+
+ ${COMMON_SRCS}
+ ${RTA_CORE_SRCS}
+ ${RTA_CONFIG_SRCS}
+ ${RTA_COMPONENTS_SRCS}
+ ${RTA_CONNECTORS_SRCS}
+ ${RTA_COMMANDS_SRCS}
+ )
+
+add_library(ccnx_transport_rta STATIC ${TRANSPORT_RTA_SOURCE_FILES})
+add_library(ccnx_transport_rta.shared SHARED ${TRANSPORT_RTA_SOURCE_FILES})
+
+set_target_properties(ccnx_transport_rta.shared PROPERTIES
+ C_STANDARD 99
+ SOVERSION 1
+ VERSION 1.0
+ OUTPUT_NAME ccnx_transport_rta )
+
+set(libccnx_transport_rta_libraries
+ ccnx_transport_rta
+ ccnx_transport_rta.shared
+ )
+
+foreach(lib ${libccnx_transport_rta_libraries})
+ install(TARGETS ${lib} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
+ set_property(TARGET ${lib} PROPERTY C_STANDARD 99)
+endforeach()
+
+install(FILES ${BASE_HDRS} DESTINATION include/ccnx/transport )
+install(FILES ${COMMON_HDRS} DESTINATION include/ccnx/transport/common )
+install(FILES ${TEST_TOOLS_HDRS} DESTINATION include/ccnx/transport/test_tools )
+install(FILES ${RTA_CORE_HDRS} DESTINATION include/ccnx/transport/transport_rta )
+install(FILES ${RTA_CONFIG_HDRS} DESTINATION include/ccnx/transport/transport_rta/config )
+install(FILES ${RTA_COMMANDS_HDRS} DESTINATION include/ccnx/transport/transport_rta/commands )
+
+add_subdirectory(common/test)
+add_subdirectory(transport_rta/test)
+add_subdirectory(transport_rta/commands/test)
+add_subdirectory(transport_rta/components/test)
+add_subdirectory(transport_rta/config/test)
+add_subdirectory(transport_rta/connectors/test)
+add_subdirectory(transport_rta/core/test)
diff --git a/libccnx-transport-rta/ccnx/transport/README b/libccnx-transport-rta/ccnx/transport/README
new file mode 100644
index 00000000..4b346689
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/README
@@ -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.
+ */
+
+common/
+
+The general transport framework, including the TransportMessage that
+crosses the boundary up to the User API framework.
+
+transport_rta/
+
+A "Ready To Assemble" transport with modular pieces.
+
diff --git a/libccnx-transport-rta/ccnx/transport/common/ccnx_ConnectionConfig.c b/libccnx-transport-rta/ccnx/transport/common/ccnx_ConnectionConfig.c
new file mode 100644
index 00000000..3792d80b
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/ccnx_ConnectionConfig.c
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+/**
+ * These are subsystems instantiated within components
+ * They define per-connection behavior, not stack structure.
+ *
+ */
+#include <config.h>
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+struct ccnx_connection_config {
+ PARCJSON *connjson;
+};
+
+bool
+ccnxConnectionConfig_IsValid(const CCNxConnectionConfig *config)
+{
+ bool result = false;
+ if (config != NULL) {
+ result = true;
+ }
+ return result;
+}
+
+void
+ccnxConnectionConfig_AssertValid(const CCNxConnectionConfig *config)
+{
+ assertTrue(ccnxConnectionConfig_IsValid(config), "CCNxConnectionConfig instance is invalid.");
+}
+
+CCNxConnectionConfig *
+ccnxConnectionConfig_Create(void)
+{
+ CCNxConnectionConfig *config = parcMemory_AllocateAndClear(sizeof(CCNxConnectionConfig));
+ assertNotNull(config, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CCNxConnectionConfig));
+ config->connjson = parcJSON_Create();
+ return config;
+}
+
+void
+ccnxConnectionConfig_Destroy(CCNxConnectionConfig **connectionConfigPtr)
+{
+ assertNotNull(connectionConfigPtr, "Parameter must be non-null double pointer");
+
+ CCNxConnectionConfig *config = *connectionConfigPtr;
+ ccnxConnectionConfig_OptionalAssertValid(config);
+
+ parcJSON_Release(&config->connjson);
+ parcMemory_Deallocate((void **) &config);
+ *connectionConfigPtr = NULL;
+}
+
+PARCJSON *
+ccnxConnectionConfig_GetJson(const CCNxConnectionConfig *config)
+{
+ ccnxConnectionConfig_OptionalAssertValid(config);
+
+ return config->connjson;
+}
+
+CCNxConnectionConfig *
+ccnxConnectionConfig_Add(CCNxConnectionConfig *config, const char *key, PARCJSONValue *componentJson)
+{
+ ccnxConnectionConfig_OptionalAssertValid(config);
+
+ parcJSON_AddValue(config->connjson, key, componentJson);
+ return config;
+}
+
+CCNxConnectionConfig *
+ccnxConnectionConfig_Copy(const CCNxConnectionConfig *original)
+{
+ ccnxConnectionConfig_OptionalAssertValid(original);
+
+ CCNxConnectionConfig *copy = parcMemory_AllocateAndClear(sizeof(CCNxConnectionConfig));
+ assertNotNull(copy, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CCNxConnectionConfig));
+ copy->connjson = parcJSON_Copy(original->connjson);
+ return copy;
+}
+
+bool
+ccnxConnectionConfig_Equals(const CCNxConnectionConfig *x, const CCNxConnectionConfig *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ result = parcJSON_Equals(x->connjson, y->connjson);
+ }
+
+ return result;
+}
+
+void
+ccnxConnectionConfig_Display(const CCNxConnectionConfig *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "ConnectionConfig@%p {", instance);
+ PARCJSON *json = ccnxConnectionConfig_GetJson(instance);
+
+ parcJSON_Display(json, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
diff --git a/libccnx-transport-rta/ccnx/transport/common/ccnx_ConnectionConfig.h b/libccnx-transport-rta/ccnx/transport/common/ccnx_ConnectionConfig.h
new file mode 100644
index 00000000..37fbcf8c
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/ccnx_ConnectionConfig.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 ccnx_ConnectionConfig.
+ * @brief Tranport Stack Connection configuration information.
+ *
+ * These are subsystems instantiated within components
+ * They define per-connection behavior, not stack structure.
+ *
+ */
+#ifndef TransportRTA_connectionConfig_h
+#define TransportRTA_connectionConfig_h
+
+
+struct ccnx_connection_config;
+typedef struct ccnx_connection_config CCNxConnectionConfig;
+
+/**
+ * Create a `CCNxConnectionConfig` instance.
+ *
+ * The instance must be populated with configuration information before it can be used.
+ *
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A valid `CCNxConnectionConfig` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxConnectionConfig *config = ccnxConnectionConfig_Create();
+ *
+ * ccnxConnectionConfig_Destroy(&config);
+ * @endcode
+ */
+CCNxConnectionConfig *ccnxConnectionConfig_Create(void);
+
+/**
+ * Destroy previously created `CCNxConnectionConfig` instance.
+ *
+ * @param [in] configPtr A pointer to a pointer to a valid `CCNxConnectionConfig` instance that will be set to zero upon return.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxConnectionConfig *config = ccnxConnectionConfig_Create();
+ *
+ * ccnxConnectionConfig_Destroy(&config);
+ * @endcode
+ */
+void ccnxConnectionConfig_Destroy(CCNxConnectionConfig **configPtr);
+
+#ifdef CCNxTransport_DISABLE_VALIDATION
+# define ccnxConnectionConfig_OptionalAssertValid(_instance_)
+#else
+# define ccnxConnectionConfig_OptionalAssertValid(_instance_) ccnxConnectionConfig_AssertValid(_instance_)
+#endif
+
+/**
+ * Determine if an instance of `CCNxTransportConfig` 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] config A pointer to a `CCNxTransportConfig` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxConnectionConfig *config = ccnxConnectionConfig_Create();
+ * ccnxConnectionConfig_IsValid(config);
+ * ccnxConnectionConfig_Destroy(&config);
+ * }
+ * @endcode
+ */
+bool ccnxConnectionConfig_IsValid(const CCNxConnectionConfig *config);
+
+/**
+ * Assert that an instance of `CCNxTransportConfig` 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] config A pointer to a `CCNxTransportConfig` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxConnectionConfig *config = ccnxConnectionConfig_Create();
+ * ccnxConnectionConfig_AssertValid(config);
+ * ccnxConnectionConfig_Destroy(&config);
+ * }
+ * @endcode
+ */
+void ccnxConnectionConfig_AssertValid(const CCNxConnectionConfig *config);
+
+/**
+ * Determine if two `CCNxConnectionConfig` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxConnectionConfig` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `ccnxConnectionConfig_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxConnectionConfig_Equals(x, y)` must return true if and only if
+ * `ccnxConnectionConfig_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxConnectionConfig_Equals(x, y)` returns true and
+ * `ccnxConnectionConfig_Equals(y, z)` returns true,
+ * then `ccnxConnectionConfig_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxConnectionConfig_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxConnectionConfig_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid CCNxConnectionConfig instance.
+ * @param [in] y A pointer to a valid CCNxConnectionConfig instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxConnectionConfig *a = ccnxConnectionConfig_Create();
+ * CCNxConnectionConfig *b = ccnxConnectionConfig_Create();
+ *
+ * if (ccnxConnectionConfig_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * ccnxConnectionConfig_Release(&a);
+ * ccnxConnectionConfig_Release(&b);
+ * }
+ * @endcode
+ * @see ccnxConnectionConfig_HashCode
+ */
+bool ccnxConnectionConfig_Equals(const CCNxConnectionConfig *x, const CCNxConnectionConfig *y);
+
+
+/**
+ * Get the underlying JSON representation of a `CCNxConnectionConfig` instance.
+ *
+ * @param [in] config A pointer to a valid `CCNxConnectionConfig` instance.
+ *
+ * @return non-NULL A pointer to a valid PARCJSON instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *ccnxConnectionConfig_GetJson(const CCNxConnectionConfig *cssonfig);
+
+/**
+ * Add a component's configuration to the connection's configuration. Each component snippit will
+ * result in an addition like this:
+ *
+ * { "key" : { param1 : value1, param2 : value2, ... } }
+ */
+CCNxConnectionConfig *ccnxConnectionConfig_Add(CCNxConnectionConfig *connectionConfig, const char *key, PARCJSONValue *componentJson);
+
+/**
+ * Make a copy of the given CCNxConnectionConfig. The original and copy
+ * must both be destroyed.
+ */
+CCNxConnectionConfig *ccnxConnectionConfig_Copy(const CCNxConnectionConfig *original);
+
+/**
+ * Print a human readable representation of the given instance.
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] instance A pointer to the instance to display.
+ */
+void ccnxConnectionConfig_Display(const CCNxConnectionConfig *instance, int indentation);
+
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/common/ccnx_StackConfig.c b/libccnx-transport-rta/ccnx/transport/common/ccnx_StackConfig.c
new file mode 100644
index 00000000..b5b55a09
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/ccnx_StackConfig.c
@@ -0,0 +1,160 @@
+/*
+ * 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 <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <ccnx/transport/common/ccnx_StackConfig.h>
+
+struct CCNxStackConfig_ {
+ PARCJSON *stackjson;
+};
+
+static void
+_ccnxStackConfig_Finalize(CCNxStackConfig **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a CCNxStackConfig pointer.");
+
+ CCNxStackConfig *instance = *instancePtr;
+ ccnxStackConfig_OptionalAssertValid(instance);
+
+ parcJSON_Release(&instance->stackjson);
+}
+
+parcObject_ImplementAcquire(ccnxStackConfig, CCNxStackConfig);
+
+parcObject_ImplementRelease(ccnxStackConfig, CCNxStackConfig);
+
+parcObject_ExtendPARCObject(CCNxStackConfig, _ccnxStackConfig_Finalize, ccnxStackConfig_Copy, ccnxStackConfig_ToString, ccnxStackConfig_Equals, NULL, ccnxStackConfig_HashCode, ccnxStackConfig_ToJSON);
+
+void
+ccnxStackConfig_AssertValid(const CCNxStackConfig *instance)
+{
+ assertTrue(ccnxStackConfig_IsValid(instance),
+ "CCNxStackConfig is not valid.");
+}
+
+CCNxStackConfig *
+ccnxStackConfig_Create(void)
+{
+ CCNxStackConfig *result = parcObject_CreateInstance(CCNxStackConfig);
+ if (result != NULL) {
+ result->stackjson = parcJSON_Create();
+ }
+
+ return result;
+}
+
+CCNxStackConfig *
+ccnxStackConfig_Copy(const CCNxStackConfig *original)
+{
+ ccnxStackConfig_OptionalAssertValid(original);
+
+ CCNxStackConfig *result = parcObject_CreateInstance(CCNxStackConfig);
+
+ result->stackjson = parcJSON_Copy(original->stackjson);
+
+ return result;
+}
+
+void
+ccnxStackConfig_Display(const CCNxStackConfig *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "CCNxStackConfig@%p {", instance);
+ PARCJSON *json = ccnxStackConfig_GetJson(instance);
+
+ parcJSON_Display(json, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+ccnxStackConfig_Equals(const CCNxStackConfig *x, const CCNxStackConfig *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ result = parcJSON_Equals(x->stackjson, y->stackjson);
+ }
+
+ return result;
+}
+
+bool
+ccnxStackConfig_IsValid(const CCNxStackConfig *instance)
+{
+ bool result = false;
+ if (instance != NULL) {
+ result = true;
+ }
+ return result;
+}
+
+PARCJSON *
+ccnxStackConfig_ToJSON(const CCNxStackConfig *instance)
+{
+ ccnxStackConfig_OptionalAssertValid(instance);
+
+ return instance->stackjson;
+}
+
+char *
+ccnxStackConfig_ToString(const CCNxStackConfig *instance)
+{
+ PARCJSON *json = ccnxStackConfig_ToJSON(instance);
+
+ char *result = parcJSON_ToString(json);
+
+ return result;
+}
+
+PARCJSONValue *
+ccnxStackConfig_Get(const CCNxStackConfig *config, const char *componentKey)
+{
+ ccnxStackConfig_OptionalAssertValid(config);
+ PARCJSONValue *value = parcJSON_GetValueByName(config->stackjson, componentKey);
+ return value;
+}
+
+PARCHashCode
+ccnxStackConfig_HashCode(const CCNxStackConfig *config)
+{
+ ccnxStackConfig_OptionalAssertValid(config);
+ return parcJSON_HashCode(config->stackjson);
+}
+
+CCNxStackConfig *
+ccnxStackConfig_Add(CCNxStackConfig *config, const char *componentKey, PARCJSONValue *jsonObject)
+{
+ ccnxStackConfig_OptionalAssertValid(config);
+
+ parcJSON_AddValue(config->stackjson, componentKey, jsonObject);
+ return config;
+}
+
+PARCJSON *
+ccnxStackConfig_GetJson(const CCNxStackConfig *config)
+{
+ ccnxStackConfig_OptionalAssertValid(config);
+
+ return (config->stackjson);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/common/ccnx_StackConfig.h b/libccnx-transport-rta/ccnx/transport/common/ccnx_StackConfig.h
new file mode 100644
index 00000000..9c3fbbf1
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/ccnx_StackConfig.h
@@ -0,0 +1,327 @@
+/*
+ * 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_StackConfig.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef TransportLibrary_ccnx_StackConfig
+#define TransportLibrary_ccnx_StackConfig
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+
+struct CCNxStackConfig_;
+typedef struct CCNxStackConfig_ CCNxStackConfig;
+
+/**
+ * Increase the number of references to a `CCNxStackConfig` instance.
+ *
+ * Note that new `CCNxStackConfig` is not created,
+ * only that the given `CCNxStackConfig` reference count is incremented.
+ * Discard the reference by invoking `ccnxStackConfig_Release`.
+ *
+ * @param [in] instance A pointer to a valid CCNxStackConfig instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *a = ccnxStackConfig_Create();
+ *
+ * CCNxStackConfig *b = ccnxStackConfig_Acquire();
+ *
+ * ccnxStackConfig_Release(&a);
+ * ccnxStackConfig_Release(&b);
+ * }
+ * @endcode
+ */
+CCNxStackConfig *ccnxStackConfig_Acquire(const CCNxStackConfig *instance);
+
+#ifdef TransportLibrary_DISABLE_VALIDATION
+# define ccnxStackConfig_OptionalAssertValid(_instance_)
+#else
+# define ccnxStackConfig_OptionalAssertValid(_instance_) ccnxStackConfig_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `CCNxStackConfig` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid CCNxStackConfig instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *a = ccnxStackConfig_Create();
+ *
+ * ccnxStackConfig_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * ccnxStackConfig_Release(&b);
+ * }
+ * @endcode
+ */
+void ccnxStackConfig_AssertValid(const CCNxStackConfig *instance);
+
+/**
+ * Create an instance of CCNxStackConfig
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid CCNxStackConfig instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *a = ccnxStackConfig_Create();
+ *
+ * ccnxStackConfig_Release(&b);
+ * }
+ * @endcode
+ */
+CCNxStackConfig *ccnxStackConfig_Create(void);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid CCNxStackConfig instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `CCNxStackConfig` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *a = ccnxStackConfig_Create();
+ *
+ * CCNxStackConfig *copy = ccnxStackConfig_Copy(&b);
+ *
+ * ccnxStackConfig_Release(&b);
+ * ccnxStackConfig_Release(&copy);
+ * }
+ * @endcode
+ */
+CCNxStackConfig *ccnxStackConfig_Copy(const CCNxStackConfig *original);
+
+/**
+ * Print a human readable representation of the given `CCNxStackConfig`.
+ *
+ * @param [in] instance A pointer to a valid CCNxStackConfig instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *a = ccnxStackConfig_Create();
+ *
+ * ccnxStackConfig_Display(a, 0);
+ *
+ * ccnxStackConfig_Release(&b);
+ * }
+ * @endcode
+ */
+void ccnxStackConfig_Display(const CCNxStackConfig *instance, int indentation);
+
+/**
+ * Determine if two `CCNxStackConfig` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxStackConfig` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `ccnxStackConfig_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxStackConfig_Equals(x, y)` must return true if and only if
+ * `ccnxStackConfig_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxStackConfig_Equals(x, y)` returns true and
+ * `ccnxStackConfig_Equals(y, z)` returns true,
+ * then `ccnxStackConfig_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxStackConfig_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxStackConfig_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid CCNxStackConfig instance.
+ * @param [in] y A pointer to a valid CCNxStackConfig instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *a = ccnxStackConfig_Create();
+ * CCNxStackConfig *b = ccnxStackConfig_Create();
+ *
+ * if (ccnxStackConfig_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * ccnxStackConfig_Release(&a);
+ * ccnxStackConfig_Release(&b);
+ * }
+ * @endcode
+ * @see ccnxStackConfig_HashCode
+ */
+bool ccnxStackConfig_Equals(const CCNxStackConfig *x, const CCNxStackConfig *y);
+
+/**
+ * Determine if an instance of `CCNxStackConfig` 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] instance A pointer to a valid CCNxStackConfig instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *a = ccnxStackConfig_Create();
+ *
+ * if (ccnxStackConfig_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * ccnxStackConfig_Release(&b);
+ * }
+ * @endcode
+ *
+ */
+bool ccnxStackConfig_IsValid(const CCNxStackConfig *instance);
+
+/**
+ * Release a previously acquired reference to the given `CCNxStackConfig` 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] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *a = ccnxStackConfig_Create();
+ *
+ * ccnxStackConfig_Release(&a);
+ * }
+ * @endcode
+ */
+void ccnxStackConfig_Release(CCNxStackConfig **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid CCNxStackConfig instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *a = ccnxStackConfig_Create();
+ *
+ * PARCJSON *json = ccnxStackConfig_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * ccnxStackConfig_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *ccnxStackConfig_ToJSON(const CCNxStackConfig *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `CCNxStackConfig`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid CCNxStackConfig instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *a = ccnxStackConfig_Create();
+ *
+ * char *string = ccnxStackConfig_ToString(a);
+ *
+ * ccnxStackConfig_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see ccnxStackConfig_Display
+ */
+char *ccnxStackConfig_ToString(const CCNxStackConfig *instance);
+
+PARCJSONValue *ccnxStackConfig_Get(const CCNxStackConfig *config, const char *componentKey);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of the `HashCode` function is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information in the 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 instances must produce the same result.
+ *
+ * It is not required that if two instances are unequal according to the `Equals` function,
+ * then calling the `HashCode` function
+ * on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to the `CCNxStackConfig` instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *buffer = ccnxStackConfig_Allocate(10);
+ * PARCHashCode hash = ccnxStackConfig_HashCode(buffer);
+ * ccnxStackConfig_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCHashCode ccnxStackConfig_HashCode(const CCNxStackConfig *instance);
+
+CCNxStackConfig *ccnxStackConfig_Add(CCNxStackConfig *config, const char *componentKey, PARCJSONValue *jsonObject);
+
+PARCJSON *ccnxStackConfig_GetJson(const CCNxStackConfig *config);
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/common/ccnx_TransportConfig.c b/libccnx-transport-rta/ccnx/transport/common/ccnx_TransportConfig.c
new file mode 100644
index 00000000..f1d55e6c
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/ccnx_TransportConfig.c
@@ -0,0 +1,120 @@
+/*
+ * 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 <LongBow/runtime.h>
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+struct transport_config {
+ CCNxStackConfig *stackConfig;
+ CCNxConnectionConfig *connConfig;
+};
+
+bool
+ccnxTransportConfig_IsValid(const CCNxTransportConfig *transportConfig)
+{
+ bool result = false;
+
+ if (transportConfig != NULL) {
+ if (ccnxStackConfig_IsValid(transportConfig->stackConfig)) {
+ if (ccnxConnectionConfig_IsValid(transportConfig->connConfig)) {
+ result = true;
+ }
+ }
+ }
+ return result;
+}
+
+void
+ccnxTransportConfig_AssertValid(const CCNxTransportConfig *config)
+{
+ assertTrue(ccnxTransportConfig_IsValid(config), "CCNxTransportConfig instance is invalid.");
+}
+
+CCNxTransportConfig *
+ccnxTransportConfig_Create(CCNxStackConfig *stackConfig, CCNxConnectionConfig *connConfig)
+{
+ ccnxStackConfig_OptionalAssertValid(stackConfig);
+ ccnxConnectionConfig_OptionalAssertValid(connConfig);
+
+ CCNxTransportConfig *result = parcMemory_AllocateAndClear(sizeof(CCNxTransportConfig));
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CCNxTransportConfig));
+ result->stackConfig = ccnxStackConfig_Acquire(stackConfig);
+ result->connConfig = connConfig;
+ return result;
+}
+
+void
+ccnxTransportConfig_Destroy(CCNxTransportConfig **transportConfigPtr)
+{
+ assertNotNull(transportConfigPtr, "Parameter must be non-null double pointer");
+ ccnxTransportConfig_OptionalAssertValid(*transportConfigPtr);
+
+ CCNxTransportConfig *transConfig = *transportConfigPtr;
+ ccnxStackConfig_Release(&transConfig->stackConfig);
+ ccnxConnectionConfig_Destroy(&transConfig->connConfig);
+ parcMemory_Deallocate((void **) &transConfig);
+ *transportConfigPtr = NULL;
+}
+
+CCNxStackConfig *
+ccnxTransportConfig_GetStackConfig(const CCNxTransportConfig *transportConfig)
+{
+ ccnxTransportConfig_OptionalAssertValid(transportConfig);
+
+ return transportConfig->stackConfig;
+}
+
+CCNxConnectionConfig *
+ccnxTransportConfig_GetConnectionConfig(const CCNxTransportConfig *transportConfig)
+{
+ ccnxTransportConfig_OptionalAssertValid(transportConfig);
+
+ return transportConfig->connConfig;
+}
+
+bool
+ccnxTransportConfig_Equals(const CCNxTransportConfig *x, const CCNxTransportConfig *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (ccnxStackConfig_Equals(x->stackConfig, y->stackConfig)) {
+ result = ccnxConnectionConfig_Equals(x->connConfig, y->connConfig);
+ }
+ }
+
+ return result;
+}
+
+CCNxTransportConfig *
+ccnxTransportConfig_Copy(const CCNxTransportConfig *original)
+{
+ ccnxTransportConfig_OptionalAssertValid(original);
+
+ CCNxTransportConfig *copy = parcMemory_AllocateAndClear(sizeof(CCNxTransportConfig));
+ assertNotNull(copy, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CCNxTransportConfig));
+
+ copy->stackConfig = ccnxStackConfig_Copy(original->stackConfig);
+ copy->connConfig = ccnxConnectionConfig_Copy(original->connConfig);
+ return copy;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/common/ccnx_TransportConfig.h b/libccnx-transport-rta/ccnx/transport/common/ccnx_TransportConfig.h
new file mode 100644
index 00000000..e85cc5f9
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/ccnx_TransportConfig.h
@@ -0,0 +1,229 @@
+/*
+ * 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_TransportConfig.h
+ * @brief The Transport Configuration information.
+ *
+ * The API composes the stack and connection parameters using these functions.
+ * The examples below are for the RTA Transport.
+ *
+ * <code>
+ * CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+ * ccnxStackConfig_AppendComponents(stackConfig, { RtaComponentNames[API_CONNECTOR], RtaComponentNames[FC_VEGAS],
+ * RtaComponentNames[CODEC_CCNB], RtaComponentNames[FWD_CCND] } );
+ *
+ * ccnxStackConfig_AppendApiConnector(stackConfig);
+ * ccnxStackConfig_AppendVegasFlowController(stackConfig);
+ * ccnxStackConfig_AppendCcndCodec(stackConfig);
+ * ccnxStackConfig_AppendCcndForwarder(stackConfig);
+ *
+ * CCNxConnectionConfig *connConfig = ccnxConnectionConfig_Create();
+ * ccnxConnectionConfig_publicKeySignerPkcs12Store(connConfig, "/Users/mmosko/keystore.p12", "123abc");
+ * ccnxConnectionConfig_InMemoryVerifier(connConfig);
+ *
+ *
+ * RtaCommand *cmdCreateStack = rtaCommand_CreateStack( (CommandCreateStack) { .stack_id = 7, .params = ccnxStackConfig_GetJson(stackConfig) } );
+ * rtaCommand_write(cmdCreateStack, command_fd);
+ * ccnxStackConfig_Release(&stackConfig);
+ *
+ * RtaCommand *cmdOpen = rtaCommand_Open( (CommandOpen) { .stack_id = 7, .api_fd = 12, .transport_fd = 13, .params = connecitonConfig_GetJson(connConfig) } );
+ * rtaCommand_write(cmdCreateStack, command_fd);
+ * ccnxConnectionConfig_Destroy(&connConfig);
+ * </code>
+ *
+ */
+#ifndef Libccnx_transport_Configuration_h
+#define Libccnx_transport_Configuration_h
+
+#include <stdarg.h>
+
+#include <ccnx/transport/common/ccnx_StackConfig.h>
+#include <ccnx/transport/common/ccnx_ConnectionConfig.h>
+
+struct transport_config;
+typedef struct transport_config CCNxTransportConfig;
+
+/**
+ * Create a `CCNxTransportConfig` instance.
+ *
+ * The instance must be populated with configuration information before it can be used.
+ *
+ * @param [in] stackConfig A pointer to a valid `CCNxStackConfig` instance.
+ * @param [in] connectionConfig A pointer to a valid `CCNxConnectionConfig` instance.
+ * @return NULL An error occurred.
+ * @return non-NULL A valid `CCNxTransportConfig` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connectionConfig);
+ *
+ * ccnxTransportConfig_Destroy(&config);
+ * @endcode
+ */
+CCNxTransportConfig *ccnxTransportConfig_Create(CCNxStackConfig *stackConfig, CCNxConnectionConfig *connectionConfig);
+
+#ifdef CCNxTransport_DISABLE_VALIDATION
+# define ccnxTransportConfig_OptionalAssertValid(_instance_)
+#else
+# define ccnxTransportConfig_OptionalAssertValid(_instance_) ccnxTransportConfig_AssertValid(_instance_)
+#endif
+/**
+ * Assert that an instance of `CCNxTransportConfig` 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] config A pointer to a `CCNxTransportConfig` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connectionConfig);
+ * ccnxTransportConfig_AssertValid(config);
+ * ccnxTransportConfig_Destroy(&config);
+ * }
+ * @endcode
+ * @see ccnxTransportConfig_IsValid
+ */
+void ccnxTransportConfig_AssertValid(const CCNxTransportConfig *config);
+
+/**
+ * Destroy previously created `CCNxTransportConfig` instance.
+ *
+ * @param [in] configPtr A pointer to a pointer to a valid `CCNxTransportConfig` instance that will be set to zero upon return.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connectionConfig);
+ *
+ * ccnxTransportConfig_Destroy(&config);
+ * }
+ * @endcode
+ */
+void ccnxTransportConfig_Destroy(CCNxTransportConfig **configPtr);
+
+/**
+ * Get the `CCNxStackConfig` instance in the given `CCNxTransportConfig`
+ *
+ * @param [in] config A pointer to a valid `CCNxTransportConfig` instance.
+ *
+ * @return A pointer to the `CCNxStackConfig` instance in the given `CCNxTransportConfig`
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connectionConfig);
+ *
+ * CCNxStackConfig *stack = ccnxTransportConfig_GetStackConfig(config);
+ *
+ * ccnxTransportConfig_Destroy(&config);
+ * }
+ * @endcode
+ */
+CCNxStackConfig *ccnxTransportConfig_GetStackConfig(const CCNxTransportConfig *config);
+
+/**
+ * Get the `CCNxConnectionConfig` instance in the given `CCNxTransportConfig`
+ *
+ * @param [in] config A pointer to a valid `CCNxTransportConfig` instance.
+ *
+ * @return A pointer to the `CCNxConnectionConfig` instance in the given `CCNxTransportConfig`
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connectionConfig);
+ *
+ * CCNxConnectionConfig *connection = ccnxTransportConfig_GetConnectionConfig(config);
+ *
+ * ccnxTransportConfig_Destroy(&config);
+ * }
+ * @endcode
+ */
+CCNxConnectionConfig *ccnxTransportConfig_GetConnectionConfig(const CCNxTransportConfig *config);
+
+/**
+ * Determine if an instance of `CCNxTransportConfig` 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] config A pointer to a `CCNxTransportConfig` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connectionConfig);
+ * ccnxTransportConfig_IsValid(config);
+ * ccnxTransportConfig_Destroy(&config);
+ * }
+ * @endcode
+ * @see ccnxTransportConfig_AssertValid
+ */
+bool ccnxTransportConfig_IsValid(const CCNxTransportConfig *config);
+/**
+ * Determine if two `CCNxTransportConfig` instances are equal.
+ *
+ * The following equivalence relations on non-null `CCNxTransportConfig` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `ccnxTransportConfig_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `ccnxTransportConfig_Equals(x, y)` must return true if and only if
+ * `ccnxTransportConfig_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `ccnxTransportConfig_Equals(x, y)` returns true and
+ * `ccnxTransportConfig_Equals(y, z)` returns true,
+ * then `ccnxTransportConfig_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `ccnxTransportConfig_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `ccnxTransportConfig_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid CCNxTransportConfig instance.
+ * @param [in] y A pointer to a valid CCNxTransportConfig instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxTransportConfig *a = ccnxTransportConfig_Create();
+ * CCNxTransportConfig *b = ccnxTransportConfig_Create();
+ *
+ * if (ccnxTransportConfig_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * ccnxTransportConfig_Release(&a);
+ * ccnxTransportConfig_Release(&b);
+ * }
+ * @endcode
+ * @see ccnxTransportConfig_HashCode
+ */
+bool ccnxTransportConfig_Equals(const CCNxTransportConfig *x, const CCNxTransportConfig *y);
+
+/**
+ * Make a copy of the given TransportConfig. The original and copy
+ * must both be destroyed.
+ */
+CCNxTransportConfig *ccnxTransportConfig_Copy(const CCNxTransportConfig *original);
+#endif // Libccnx_transport_Configuration_h
diff --git a/libccnx-transport-rta/ccnx/transport/common/test/.gitignore b/libccnx-transport-rta/ccnx/transport/common/test/.gitignore
new file mode 100644
index 00000000..6fd12a5f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/test/.gitignore
@@ -0,0 +1,4 @@
+test_transport_MetaMessage
+test_ccnx_ConnectionConfig
+test_ccnx_StackConfig
+test_ccnx_TransportConfig
diff --git a/libccnx-transport-rta/ccnx/transport/common/test/CMakeLists.txt b/libccnx-transport-rta/ccnx/transport/common/test/CMakeLists.txt
new file mode 100644
index 00000000..c964fc69
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/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_transport_MetaMessage
+ test_ccnx_ConnectionConfig
+ test_ccnx_StackConfig
+ test_ccnx_TransportConfig
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-transport-rta/ccnx/transport/common/test/test_ccnx_ConnectionConfig.c b/libccnx-transport-rta/ccnx/transport/common/test/test_ccnx_ConnectionConfig.c
new file mode 100644
index 00000000..2bc4d121
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/test/test_ccnx_ConnectionConfig.c
@@ -0,0 +1,183 @@
+/*
+ * 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_ConnectionConfig.c"
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(ccnx_ConnectionConfig)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified here, but every test must be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ 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_ConnectionConfig)
+{
+ 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_ConnectionConfig)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxConnectionConfig_Add);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxConnectionConfig_AssertValid);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxConnectionConfig_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxConnectionConfig_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxConnectionConfig_CreateDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxConnectionConfig_Display);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxConnectionConfig_GetJson);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxConnectionConfig_IsValid);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxConnectionConfig_Add)
+{
+ CCNxConnectionConfig *config = ccnxConnectionConfig_Create();
+
+ PARCJSONValue *val = parcJSONValue_CreateFromNULL();
+ ccnxConnectionConfig_Add(config, "key", val);
+ parcJSONValue_Release(&val);
+
+ ccnxConnectionConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxConnectionConfig_AssertValid)
+{
+ CCNxConnectionConfig *config = ccnxConnectionConfig_Create();
+ ccnxConnectionConfig_AssertValid(config);
+ ccnxConnectionConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxConnectionConfig_Equals)
+{
+ CCNxConnectionConfig *x = ccnxConnectionConfig_Create();
+ CCNxConnectionConfig *y = ccnxConnectionConfig_Create();
+ CCNxConnectionConfig *z = ccnxConnectionConfig_Create();
+ CCNxConnectionConfig *u1 = ccnxConnectionConfig_Create();
+ PARCJSONValue *val = parcJSONValue_CreateFromNULL();
+ ccnxConnectionConfig_Add(u1, "key", val);
+ parcJSONValue_Release(&val);
+
+ parcObjectTesting_AssertEqualsFunction(ccnxConnectionConfig_Equals, x, y, z, u1);
+
+ ccnxConnectionConfig_Destroy(&x);
+ ccnxConnectionConfig_Destroy(&y);
+ ccnxConnectionConfig_Destroy(&z);
+ ccnxConnectionConfig_Destroy(&u1);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxConnectionConfig_Copy)
+{
+ CCNxConnectionConfig *x = ccnxConnectionConfig_Create();
+ PARCJSONValue *val = parcJSONValue_CreateFromNULL();
+ ccnxConnectionConfig_Add(x, "key", val);
+ parcJSONValue_Release(&val);
+
+ CCNxConnectionConfig *y = ccnxConnectionConfig_Copy(x);
+ assertTrue(ccnxConnectionConfig_Equals(x, y), "Expected the copy to be equal to the original");
+ ccnxConnectionConfig_Destroy(&x);
+ ccnxConnectionConfig_Destroy(&y);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxConnectionConfig_CreateDestroy)
+{
+ CCNxConnectionConfig *config = ccnxConnectionConfig_Create();
+ assertNotNull(config, "Expected non-NULL result from ccnxConnectionConfig_Create.");
+ ccnxConnectionConfig_Destroy(&config);
+ assertNull(config, "Expected NULL result from ccnxConnectionConfig_Destroy");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxConnectionConfig_Display)
+{
+ CCNxConnectionConfig *config = ccnxConnectionConfig_Create();
+ ccnxConnectionConfig_Display(config, 0);
+
+ ccnxConnectionConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxConnectionConfig_GetJson)
+{
+ CCNxConnectionConfig *config = ccnxConnectionConfig_Create();
+
+ PARCJSON *json = ccnxConnectionConfig_GetJson(config);
+
+ assertNotNull(json, "Expected ccnxConnectionConfig_GetJson result to be non-null.");
+ ccnxConnectionConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxConnectionConfig_IsValid)
+{
+ CCNxConnectionConfig *config = ccnxConnectionConfig_Create();
+ assertTrue(ccnxConnectionConfig_IsValid(config), "Expected ccnxConnectionConfig_Create result to be valid.");
+
+ ccnxConnectionConfig_Destroy(&config);
+ assertFalse(ccnxConnectionConfig_IsValid(config), "Expected ccnxConnectionConfig_Destroy result to be invalid.");
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ConnectionConfig);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/common/test/test_ccnx_StackConfig.c b/libccnx-transport-rta/ccnx/transport/common/test/test_ccnx_StackConfig.c
new file mode 100644
index 00000000..4f1ee7dc
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/test/test_ccnx_StackConfig.c
@@ -0,0 +1,226 @@
+/*
+ * 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_StackConfig.c"
+#include <LongBow/unit-test.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(ccnx_StackConfig)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified here, but every test must be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ 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_StackConfig)
+{
+ 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_StackConfig)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxStackConfig_AddGet);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxStackConfig_AssertValid);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxStackConfig_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxStackConfig_CreateAcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxStackConfig_Display);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxStackConfig_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxStackConfig_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxStackConfig_GetJson);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxStackConfig_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxStackConfig_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxStackConfig_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxStackConfig_AddGet)
+{
+ CCNxStackConfig *instance = ccnxStackConfig_Create();
+
+ PARCJSONValue *expected = parcJSONValue_CreateFromNULL();
+ ccnxStackConfig_Add(instance, "key", expected);
+
+ PARCJSONValue *actual = ccnxStackConfig_Get(instance, "key");
+
+ assertTrue(parcJSONValue_Equals(expected, actual), "ccnxStackConfig_Get did not return what was 'added'");
+
+ parcJSONValue_Release(&expected);
+
+ ccnxStackConfig_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxStackConfig_AssertValid)
+{
+ CCNxStackConfig *instance = ccnxStackConfig_Create();
+ ccnxStackConfig_AssertValid(instance);
+
+ ccnxStackConfig_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxStackConfig_Copy)
+{
+ CCNxStackConfig *instance = ccnxStackConfig_Create();
+ CCNxStackConfig *copy = ccnxStackConfig_Copy(instance);
+ assertTrue(ccnxStackConfig_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ ccnxStackConfig_Release(&instance);
+ ccnxStackConfig_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxStackConfig_CreateAcquireRelease)
+{
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+ assertNotNull(config, "Expected non-NULL result from ccnxConnectionConfig_Create.");
+
+ CCNxStackConfig *reference = ccnxStackConfig_Acquire(config);
+
+ ccnxStackConfig_Release(&config);
+ assertNull(config, "Expected NULL result from ccnxConnectionConfig_Destroy");
+ ccnxStackConfig_Release(&reference);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxStackConfig_Display)
+{
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+ ccnxStackConfig_Display(config, 1);
+
+ ccnxStackConfig_Release(&config);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxStackConfig_Equals)
+{
+ CCNxStackConfig *x = ccnxStackConfig_Create();
+ CCNxStackConfig *y = ccnxStackConfig_Create();
+ CCNxStackConfig *z = ccnxStackConfig_Create();
+
+ CCNxStackConfig *u1 = ccnxStackConfig_Create();
+ PARCJSONValue *val = parcJSONValue_CreateFromNULL();
+ ccnxStackConfig_Add(u1, "key", val);
+ parcJSONValue_Release(&val);
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ ccnxStackConfig_Release(&x);
+ ccnxStackConfig_Release(&y);
+ ccnxStackConfig_Release(&z);
+ ccnxStackConfig_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxStackConfig_HashCode)
+{
+ CCNxStackConfig *instance = ccnxStackConfig_Create();
+ uint64_t hashCode = ccnxStackConfig_HashCode(instance);
+ printf("%" PRIu64 "\n", hashCode);
+ ccnxStackConfig_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxStackConfig_GetJson)
+{
+ CCNxStackConfig *instance = ccnxStackConfig_Create();
+ PARCJSON *json = ccnxStackConfig_GetJson(instance);
+
+ assertNotNull(json, "Expected non-null JSON");
+ ccnxStackConfig_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxStackConfig_IsValid)
+{
+ CCNxStackConfig *instance = ccnxStackConfig_Create();
+ assertTrue(ccnxStackConfig_IsValid(instance), "Expected ccnxStackConfig_Create to result in a valid instance.");
+
+ ccnxStackConfig_Release(&instance);
+ assertFalse(ccnxStackConfig_IsValid(instance), "Expected ccnxStackConfig_Create to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxStackConfig_ToJSON)
+{
+ CCNxStackConfig *instance = ccnxStackConfig_Create();
+ PARCJSON *json = ccnxStackConfig_ToJSON(instance);
+ assertNotNull(json, "Expected non-null JSON");
+
+ ccnxStackConfig_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxStackConfig_ToString)
+{
+ CCNxStackConfig *instance = ccnxStackConfig_Create();
+ char *string = ccnxStackConfig_ToString(instance);
+ assertNotNull(string, "Expected non-null ccnxStackConfig_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ ccnxStackConfig_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxStackConfig_Get)
+{
+ CCNxStackConfig *instance = ccnxStackConfig_Create();
+
+ ccnxStackConfig_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_StackConfig);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/common/test/test_ccnx_TransportConfig.c b/libccnx-transport-rta/ccnx/transport/common/test/test_ccnx_TransportConfig.c
new file mode 100644
index 00000000..8b954419
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/test/test_ccnx_TransportConfig.c
@@ -0,0 +1,226 @@
+/*
+ * 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_TransportConfig.c"
+
+#include <LongBow/unit-test.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+
+LONGBOW_TEST_RUNNER(ccnx_TransportConfig)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified here, but every test must be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ 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_TransportConfig)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_TransportConfig)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTransportConfig_AssertValid);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTransportConfig_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTransportConfig_CreateDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTransportConfig_GetConnectionConfig);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTransportConfig_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTransportConfig_GetStackConfig);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTransportConfig_IsValid_True);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxTransportConfig_IsValid_False);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTransportConfig_AssertValid)
+{
+ CCNxStackConfig *stack = ccnxStackConfig_Create();
+ CCNxConnectionConfig *connection = ccnxConnectionConfig_Create();
+
+ CCNxTransportConfig *x = ccnxTransportConfig_Create(stack, connection);
+
+ ccnxTransportConfig_AssertValid(x);
+
+ ccnxStackConfig_Release(&stack);
+
+ ccnxTransportConfig_Destroy(&x);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTransportConfig_Copy)
+{
+ CCNxStackConfig *stack = ccnxStackConfig_Create();
+ CCNxConnectionConfig *connection = ccnxConnectionConfig_Create();
+
+ CCNxTransportConfig *x = ccnxTransportConfig_Create(stack, connection);
+ assertNotNull(x, "Expected non-null result from ccnxTransportConfig_Create");
+ ccnxStackConfig_Release(&stack);
+
+ CCNxTransportConfig *y = ccnxTransportConfig_Copy(x);
+
+ assertTrue(ccnxTransportConfig_Equals(x, y), "Expected ccnxTransportConfig_Copy result to be equal to the original");
+
+ ccnxTransportConfig_Destroy(&x);
+ ccnxTransportConfig_Destroy(&y);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTransportConfig_Equals)
+{
+ CCNxStackConfig *stack = ccnxStackConfig_Create();
+ CCNxConnectionConfig *connection = ccnxConnectionConfig_Create();
+
+ CCNxTransportConfig *x = ccnxTransportConfig_Create(stack, ccnxConnectionConfig_Copy(connection));
+ CCNxTransportConfig *y = ccnxTransportConfig_Create(stack, ccnxConnectionConfig_Copy(connection));
+ CCNxTransportConfig *z = ccnxTransportConfig_Create(stack, ccnxConnectionConfig_Copy(connection));
+
+ CCNxStackConfig *otherStack = ccnxStackConfig_Create();
+ PARCJSONValue *val = parcJSONValue_CreateFromNULL();
+ ccnxStackConfig_Add(otherStack, "key", val);
+ CCNxTransportConfig *u1 = ccnxTransportConfig_Create(otherStack, ccnxConnectionConfig_Copy(connection));
+
+ CCNxConnectionConfig *otherConnection = ccnxConnectionConfig_Create();
+ ccnxConnectionConfig_Add(otherConnection, "key", val);
+
+ CCNxTransportConfig *u2 = ccnxTransportConfig_Create(stack, otherConnection);
+
+ parcObjectTesting_AssertEqualsFunction(ccnxTransportConfig_Equals, x, y, z, u1, u2);
+
+ assertTrue(ccnxTransportConfig_Equals(x, y), "Expected ccnxTransportConfig_Copy result to be equal to the original");
+
+ parcJSONValue_Release(&val);
+ ccnxStackConfig_Release(&stack);
+ ccnxStackConfig_Release(&otherStack);
+ ccnxConnectionConfig_Destroy(&connection);
+
+ ccnxTransportConfig_Destroy(&x);
+ ccnxTransportConfig_Destroy(&y);
+ ccnxTransportConfig_Destroy(&z);
+ ccnxTransportConfig_Destroy(&u1);
+ ccnxTransportConfig_Destroy(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTransportConfig_CreateDestroy)
+{
+ CCNxStackConfig *stack = ccnxStackConfig_Create();
+ CCNxConnectionConfig *connection = ccnxConnectionConfig_Create();
+
+ CCNxTransportConfig *x = ccnxTransportConfig_Create(stack, connection);
+ assertNotNull(x, "Expected non-null result from ccnxTransportConfig_Create");
+ ccnxStackConfig_Release(&stack);
+
+ ccnxTransportConfig_Destroy(&x);
+ assertNull(x, "Expected null result from ccnxStackConfig_Release");
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTransportConfig_GetConnectionConfig)
+{
+ CCNxStackConfig *stack = ccnxStackConfig_Create();
+ CCNxConnectionConfig *connection = ccnxConnectionConfig_Create();
+
+ CCNxTransportConfig *config = ccnxTransportConfig_Create(stack, connection);
+ ccnxStackConfig_Release(&stack);
+
+ CCNxConnectionConfig *actual = ccnxTransportConfig_GetConnectionConfig(config);
+
+ assertTrue(connection == actual, "Expected ccnxTransportConfig_GetConnectionConfig to return the original.");
+
+ ccnxTransportConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTransportConfig_GetStackConfig)
+{
+ CCNxStackConfig *stack = ccnxStackConfig_Create();
+ CCNxConnectionConfig *connection = ccnxConnectionConfig_Create();
+
+ CCNxTransportConfig *config = ccnxTransportConfig_Create(stack, connection);
+
+ CCNxStackConfig *actual = ccnxTransportConfig_GetStackConfig(config);
+
+ assertTrue(stack == actual, "Expected ccnxTransportConfig_GetStackConfig to return the original.");
+
+ ccnxStackConfig_Release(&stack);
+ ccnxTransportConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTransportConfig_IsValid_True)
+{
+ CCNxStackConfig *stack = ccnxStackConfig_Create();
+ CCNxConnectionConfig *connection = ccnxConnectionConfig_Create();
+
+ CCNxTransportConfig *x = ccnxTransportConfig_Create(stack, connection);
+ assertTrue(ccnxTransportConfig_IsValid(x), "Expected ccnxTransportConfig_Create to return a valid instance.");
+ ccnxStackConfig_Release(&stack);
+
+ ccnxTransportConfig_Destroy(&x);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxTransportConfig_IsValid_False)
+{
+ assertFalse(ccnxTransportConfig_IsValid(NULL), "Expected NULL to be an invalid instance.");
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_TransportConfig);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/common/test/test_transport.c b/libccnx-transport-rta/ccnx/transport/common/test/test_transport.c
new file mode 100644
index 00000000..2642acd6
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/test/test_transport.c
@@ -0,0 +1,136 @@
+/*
+ * 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 "../transport.c"
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_TestingMemory.h>
+
+LONGBOW_TEST_RUNNER(transport)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified here, but every test must be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ 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(transport)
+{
+ 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(transport)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, Transport_Create_RTA);
+ LONGBOW_RUN_TEST_CASE(Global, Transport_Close);
+ LONGBOW_RUN_TEST_CASE(Global, Transport_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, Transport_Open);
+ LONGBOW_RUN_TEST_CASE(Global, Transport_PassCommand);
+ LONGBOW_RUN_TEST_CASE(Global, Transport_Recv);
+ LONGBOW_RUN_TEST_CASE(Global, Transport_Send);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+ if (parcTestingMemory_ExpectedOutstanding(0, "%s", longBowTestCase_GetFullName(testCase)) == false) {
+ result = LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return result;
+}
+
+LONGBOW_TEST_CASE(Global, Transport_Close)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, Transport_Create_RTA)
+{
+ TransportContext *transport = Transport_Create(TRANSPORT_RTA);
+
+ Transport_Destroy(&transport);
+}
+
+LONGBOW_TEST_CASE(Global, Transport_Destroy)
+{
+ TransportContext *transport = Transport_Create(TRANSPORT_RTA);
+
+ Transport_Destroy(&transport);
+}
+
+LONGBOW_TEST_CASE(Global, Transport_Open)
+{
+ TransportContext *transport = Transport_Create(TRANSPORT_RTA);
+
+
+ Transport_Destroy(&transport);
+}
+
+LONGBOW_TEST_CASE(Global, Transport_PassCommand)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, Transport_Recv)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, Transport_Send)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(transport);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/common/test/test_transport_Message.c b/libccnx-transport-rta/ccnx/transport/common/test/test_transport_Message.c
new file mode 100644
index 00000000..ec9e3a04
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/test/test_transport_Message.c
@@ -0,0 +1,15 @@
+/*
+ * 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-transport-rta/ccnx/transport/common/test/test_transport_MetaMessage.c b/libccnx-transport-rta/ccnx/transport/common/test/test_transport_MetaMessage.c
new file mode 100644
index 00000000..3896d945
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/test/test_transport_MetaMessage.c
@@ -0,0 +1,283 @@
+/*
+ * 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 "../transport_MetaMessage.c"
+#include <stdio.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <ccnx/common/validation/ccnxValidation_CRC32C.h>
+
+LONGBOW_TEST_RUNNER(ccnx_MetaMessage)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ 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_MetaMessage)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_MetaMessage)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ccnxMetaMessage_Acquire_Release);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxMetaMessage_CreateFromContentObject);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxMetaMessage_CreateFromControl);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxMetaMessage_CreateFromInterest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxMetaMessage_Display);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxMetaMessage_GetContentObject);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxMetaMessage_GetControl);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxMetaMessage_GetInterest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxMetaMessage_IsContentObject);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxMetaMessage_IsControl);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxMetaMessage_IsInterest);
+ LONGBOW_RUN_TEST_CASE(Global, ccnxMetaMessage_EncodeDecode);
+}
+
+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, ccnxMetaMessage_Acquire_Release)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ CCNxMetaMessage *portalMessage = ccnxMetaMessage_CreateFromInterest(interest);
+
+ CCNxMetaMessage *ref1 = ccnxMetaMessage_Acquire(portalMessage);
+ CCNxMetaMessage *ref2 = ccnxMetaMessage_Acquire(portalMessage);
+ CCNxMetaMessage *ref3 = ccnxMetaMessage_Acquire(portalMessage);
+
+ ccnxMetaMessage_Release(&ref1);
+ assertNull(ref1, "Expected pointer to pointer to be null after Release()");
+
+ ccnxMetaMessage_Release(&ref2);
+ assertNull(ref2, "Expected pointer to pointer to be null after Release()");
+
+ ccnxMetaMessage_Release(&ref3);
+ assertNull(ref3, "Expected pointer to pointer to be null after Release()");
+
+ ccnxMetaMessage_Release(&portalMessage);
+ ccnxInterest_Release(&interest);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxMetaMessage_CreateFromContentObject)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ PARCBuffer *payload = parcBuffer_WrapCString("This is some data. It's not good data, but it is data.");
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+
+ CCNxMetaMessage *portalMessage = ccnxMetaMessage_CreateFromContentObject(contentObject);
+ assertNotNull(portalMessage, "Expected a non-null portal message");
+ ccnxMetaMessage_Release(&portalMessage);
+
+ ccnxContentObject_Release(&contentObject);
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+}
+
+#ifndef BUGZID_712
+LONGBOW_TEST_CASE(Global, ccnxMetaMessage_CreateFromControl)
+{
+ testUnimplemented("");
+}
+#endif // !BUGZID_712
+
+LONGBOW_TEST_CASE(Global, ccnxMetaMessage_CreateFromInterest)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+
+ CCNxMetaMessage *portalMessage = ccnxMetaMessage_CreateFromInterest(interest);
+ assertNotNull(portalMessage, "Expected a non-null portal message");
+ ccnxMetaMessage_Release(&portalMessage);
+
+ ccnxInterest_Release(&interest);
+ ccnxName_Release(&name);
+}
+
+#ifndef BUGZID_712
+LONGBOW_TEST_CASE(Global, ccnxMetaMessage_Display)
+{
+ testUnimplemented("");
+}
+#endif // !BUGZID_712
+
+LONGBOW_TEST_CASE(Global, ccnxMetaMessage_GetContentObject)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ PARCBuffer *payload = parcBuffer_WrapCString("This is some data. It's not good data, but it is data.");
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+
+ CCNxMetaMessage *portalMessage = ccnxMetaMessage_CreateFromContentObject(contentObject);
+
+ CCNxContentObject *reference = ccnxMetaMessage_GetContentObject(portalMessage);
+
+#ifndef BUGZID_712
+ // TODO: We need a ccnxContentObject_Equals()!
+ // assertTrue(ccnxContentObject_Equals(contentObject, reference), "Expected reference to equal original contentObject");
+#endif // !BUGZID_712
+ ccnxContentObject_AssertValid(reference);
+
+ ccnxMetaMessage_Release(&portalMessage);
+
+ ccnxContentObject_Release(&contentObject);
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+}
+
+#ifndef BUGZID_712
+LONGBOW_TEST_CASE(Global, ccnxMetaMessage_GetControl)
+{
+ testUnimplemented("");
+}
+#endif // !BUGZID_712
+
+LONGBOW_TEST_CASE(Global, ccnxMetaMessage_GetInterest)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ CCNxMetaMessage *portalMessage = ccnxMetaMessage_CreateFromInterest(interest);
+ CCNxInterest *reference = ccnxMetaMessage_GetInterest(portalMessage);
+
+ assertTrue(ccnxInterest_Equals(interest, reference), "Expected reference to equal original interest");
+ ccnxInterest_AssertValid(reference);
+
+ ccnxInterest_Release(&reference);
+ ccnxMetaMessage_Release(&portalMessage);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxMetaMessage_IsContentObject)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ PARCBuffer *payload = parcBuffer_WrapCString("This is some data. It's not good data, but it is data.");
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+
+ CCNxMetaMessage *portalMessage = ccnxMetaMessage_CreateFromContentObject(contentObject);
+
+ assertTrue(ccnxMetaMessage_IsContentObject(portalMessage), "Expected portal message to be an ContentObject");
+ assertFalse(ccnxMetaMessage_IsInterest(portalMessage), "Did not expect portal message to be an Interest");
+ assertFalse(ccnxMetaMessage_IsControl(portalMessage), "Did not expect portal message to be a Control message");
+
+ ccnxMetaMessage_Release(&portalMessage);
+ ccnxContentObject_Release(&contentObject);
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+}
+
+#ifndef BUGZID_712
+LONGBOW_TEST_CASE(Global, ccnxMetaMessage_IsControl)
+{
+ testUnimplemented("");
+}
+#endif // !BUGZID_712
+
+LONGBOW_TEST_CASE(Global, ccnxMetaMessage_IsInterest)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ CCNxMetaMessage *portalMessage = ccnxMetaMessage_CreateFromInterest(interest);
+
+ assertTrue(ccnxMetaMessage_IsInterest(portalMessage), "Expected portal message to be an Interest");
+ assertFalse(ccnxMetaMessage_IsContentObject(portalMessage), "Did not expect portal message to be a ContentObject");
+ assertFalse(ccnxMetaMessage_IsControl(portalMessage), "Did not expect portal message to be a Control message");
+
+ ccnxMetaMessage_Release(&portalMessage);
+ ccnxInterest_Release(&interest);
+ ccnxName_Release(&name);
+}
+
+LONGBOW_TEST_CASE(Global, ccnxMetaMessage_EncodeDecode)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ PARCSigner *signer = ccnxValidationCRC32C_CreateSigner(); // Would really be SHA256 or something.
+
+ // Encode it to wire format.
+ PARCBuffer *wireFormatBuffer = ccnxMetaMessage_CreateWireFormatBuffer(interest, signer);
+
+ // Now decode it from wireformat.
+ CCNxMetaMessage *decodedMessage = ccnxMetaMessage_CreateFromWireFormatBuffer(wireFormatBuffer);
+
+ // At this point, the unpacked dictionary should be equivalent to the original interest.
+ assertTrue(ccnxInterest_Equals(interest, decodedMessage), "Expected an equivalent interest to be unpacked");
+
+ parcBuffer_Release(&wireFormatBuffer);
+ ccnxInterest_Release(&interest);
+ ccnxMetaMessage_Release(&decodedMessage);
+ parcSigner_Release(&signer);
+}
+
+#ifndef BUGZID_712
+LONGBOW_TEST_CASE(Global, ccnxMetaMessage_Release)
+{
+ testUnimplemented("");
+}
+#endif // !BUGZID_712
+
+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_MetaMessage);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/common/test/test_transport_Stack.c b/libccnx-transport-rta/ccnx/transport/common/test/test_transport_Stack.c
new file mode 100644
index 00000000..4a10d962
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/test/test_transport_Stack.c
@@ -0,0 +1,191 @@
+/*
+ * 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 "../transport_Stack.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(transport_Stack)
+{
+ // 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(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(transport_Stack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(transport_Stack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ TransportStack *instance = transportStack_Create();
+ assertNotNull(instance, "Expected non-null result from transportStack_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(instance);
+
+ transportStack_Release(&instance);
+ assertNull(instance, "Expected null result from transportStack_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, transportStack_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, transportStack_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, transportStack_Display);
+ LONGBOW_RUN_TEST_CASE(Global, transportStack_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, transportStack_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, transportStack_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, transportStack_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, transportStack_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, transportStack_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, transportStack_Copy)
+{
+ TransportStack *instance = transportStack_Create();
+ TransportStack *copy = transportStack_Copy(instance);
+ assertTrue(transportStack_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ transportStack_Release(&instance);
+ transportStack_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, transportStack_Display)
+{
+ TransportStack *instance = transportStack_Create();
+ transportStack_Display(instance, 0);
+ transportStack_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, transportStack_Equals)
+{
+ TransportStack *x = transportStack_Create();
+ TransportStack *y = transportStack_Create();
+ TransportStack *z = transportStack_Create();
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ transportStack_Release(&x);
+ transportStack_Release(&y);
+ transportStack_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Global, transportStack_HashCode)
+{
+ TransportStack *x = transportStack_Create();
+ TransportStack *y = transportStack_Create();
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ transportStack_Release(&x);
+ transportStack_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Global, transportStack_IsValid)
+{
+ TransportStack *instance = transportStack_Create();
+ assertTrue(transportStack_IsValid(instance), "Expected transportStack_Create to result in a valid instance.");
+
+ transportStack_Release(&instance);
+ assertFalse(transportStack_IsValid(instance), "Expected transportStack_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, transportStack_ToJSON)
+{
+ TransportStack *instance = transportStack_Create();
+
+ PARCJSON *json = transportStack_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ transportStack_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, transportStack_ToString)
+{
+ TransportStack *instance = transportStack_Create();
+
+ char *string = transportStack_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from transportStack_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ transportStack_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(transport_Stack);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libccnx-transport-rta/ccnx/transport/common/transport.c b/libccnx-transport-rta/ccnx/transport/common/transport.c
new file mode 100644
index 00000000..0f9e564d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/transport.c
@@ -0,0 +1,123 @@
+/*
+ * 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 <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include "transport.h"
+#include "transport_private.h"
+#include "rta_Transport.h"
+
+struct transport_context {
+ TransportTypes transport_type;
+ struct transport_operations ops;
+ void *transport_data;
+ unsigned references;
+};
+
+// the one global transport, for now
+static TransportContext *the_context = NULL;
+
+TransportContext *
+Transport_Create(TransportTypes type)
+{
+ if (the_context == NULL) {
+ switch (type) {
+ case TRANSPORT_RTA:
+ the_context = parcMemory_Allocate(sizeof(TransportContext));
+ assertNotNull(the_context, "TransportContext could not be allocated, parcMemory_Allocate(%zu) returned NULL", sizeof(TransportContext));
+
+ the_context->references = 0;
+ the_context->ops = rta_ops;
+ the_context->transport_data = the_context->ops.Create();
+ the_context->transport_type = type;
+ break;
+
+ default:
+ fprintf(stderr, "%s unknown transport type %d\n", __func__, type);
+ abort();
+ break;
+ }
+ }
+
+ if (the_context->transport_type == type) {
+ the_context->references++;
+ return the_context;
+ }
+
+ fprintf(stderr, "%s transport type %d not of request type %d\n",
+ __func__, the_context->transport_type, type);
+ abort();
+}
+
+int
+Transport_Open(CCNxTransportConfig *transportConfig)
+{
+ assertNotNull(the_context, "The TransportContext is NULL.");
+ assertNotNull(transportConfig, "The parameter transportConfig must be a non-null CCNxTransportConfig pointer");
+ return the_context->ops.Open(the_context->transport_data, transportConfig);
+}
+
+int
+Transport_Send(int desc, CCNxMetaMessage *msg_in)
+{
+ assertNotNull(the_context, "the_context is null");
+ return the_context->ops.Send(the_context->transport_data, desc, msg_in, CCNxStackTimeout_Never);
+}
+
+TransportIOStatus
+Transport_Recv(int desc, CCNxMetaMessage **msg_out)
+{
+ return the_context->ops.Recv(the_context->transport_data, desc, msg_out, CCNxStackTimeout_Never);
+}
+
+int
+Transport_Close(int desc)
+{
+ return the_context->ops.Close(the_context->transport_data, desc);
+}
+
+int
+Transport_PassCommand(void *stackCommand)
+{
+ return the_context->ops.PassCommand(the_context->transport_data, stackCommand);
+}
+
+void
+Transport_Destroy(TransportContext **ctxPtr)
+{
+ assertNotNull(ctxPtr, "Transport_Destroy called with null context");
+ assertNotNull(*ctxPtr, "Transport_Destroy callled with reference to null");
+
+ TransportContext *ctx = *ctxPtr;
+
+ assertTrue(the_context == ctx, "Passed ctx is not the same");
+ assertTrue(ctx->references > 0, "Invalid reference count");
+
+ ctx->references--;
+ if (ctx->references == 0) {
+ ctx->ops.Destroy(&ctx->transport_data);
+ memset(ctx, 0, sizeof(TransportContext));
+ parcMemory_Deallocate((void **) &ctx);
+ ctx = NULL;
+ the_context = NULL;
+ }
+}
diff --git a/libccnx-transport-rta/ccnx/transport/common/transport.h b/libccnx-transport-rta/ccnx/transport/common/transport.h
new file mode 100644
index 00000000..1068d37d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/transport.h
@@ -0,0 +1,262 @@
+/*
+ * 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 transport.h
+ * @brief Defines the Transport API from the App API.
+ *
+ * Application interfaces use this API to communicate
+ * with the transport.
+ *
+ * An API will call transport_Create(type), to create
+ * a transport of the given type. Only type TRANSPORT_RTA
+ * is supported at this time. Only one transport may exist,
+ * so multiple calls to transport_Create() will return
+ * a reference counted pointer to the same transport.
+ * When an API is done, it should call transport_Destroy().
+ *
+ * An API opens connections with the forwarder via
+ * transport_Open(PARCJSON *). The JSON dictionary defines
+ * the properties of the protocol stack associated with the
+ * connection. When done, the API should call transport_Close()
+ * on the connection. Multiple calls with the same JSON
+ * definition will return new connecitons using the same
+ * protocol stack.
+ *
+ * See the documentation in transport_rta/core/rta_Component.h
+ * about how to write a new component for use in a protocol stack.
+ *
+ *
+ * transport_Open() requires a JSON configuration string that
+ * defines the SYSTEM and USER parameters. SYSTEM parameters
+ * define the ProtocolStack. USER parameters are variations
+ * within a ProtocolStack, such as which signing keys to use.
+ *
+ * \code{.c}
+ * {
+ * "SYSTEM" : {
+ * "COMPONENTS" : [ array of identifiers ],
+ * <component name> : { component parameters },
+ * <component name> : { component parameters }
+ * }
+ *
+ * "USER" : {
+ * <component name> : {component parameters},
+ * <component name> : {component parameters},
+ * <component name> : {component parameters}
+ * }
+ * }
+ * \endcode
+ *
+ * The COMPONENTS parameter lists the comonents in the protocol stack.
+ * The names should be taken from components.h (e.g. API_CONNECTOR).
+ *
+ * An example would be:
+ * \code{.c}
+ * {
+ * "SYSTEM" : {
+ * "COMPONENTS" : [
+ * "API_CONNECTOR",
+ * "FC_VEGAS,
+ * "VERIFY_ENUMERATED",
+ * "CODEC_TLV",
+ * "FWD_FLAN"
+ * ],
+ * "FWD_FLAN" : { "port" : 1234 },
+ * "FC_VEGAS" : { "max_cwind": 65536 }
+ * }
+ *
+ * "USER" : {
+ * "CODEC_TLV" : {
+ * "SET_SIGNING_KEYSTORE" : {
+ * "KEYSTORE_NAME" : "/Users/alice/.ccnxkeystore",
+ * "KEYSTORE_PASSWD": "1234abcd"
+ * }
+ * }
+ *
+ * "VERIFY_ENUMERATED" : {
+ * "ADD_TRUSTED_CERTS" : [
+ * <PEM encoded X.509 cert>,
+ * <PEM encoded X.509 cert>,
+ * <PEM encoded X.509 cert> ]
+ * "ADD_TRUSTED_ISSUERS" : [
+ * <PEM encoded X.509 cert> ]
+ * "ADD_TRUSTED_KEYS" : [
+ * <PEM encoded RSA public key>,
+ * <PEM encoded DSA public key>]
+ * }
+ * }
+ * }
+ * \endcode
+ *
+ */
+#ifndef CCNX_TRANSPORT_H
+#define CCNX_TRANSPORT_H
+
+#include <ccnx/transport/common/transport_MetaMessage.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+#include <ccnx/transport/common/transport_Message.h>
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+struct transport_context;
+typedef struct transport_context TransportContext;
+
+typedef enum {
+ TRANSPORT_RTA
+} TransportTypes;
+
+typedef enum TransportIOStatus {
+ TransportIOStatus_Success = 0,
+ TransportIOStatus_Error = 1,
+ TransportIOStatus_Timeout = 2
+} TransportIOStatus;
+
+typedef uint64_t CCNxStackTimeout;
+
+/**
+ * @def CCNxStackTimeout_Never
+ * The receive function is a blocking read that never times out.
+ */
+#define CCNxStackTimeout_Never NULL
+
+/*
+ * @def CCNxStackTimeout_Immediate
+ * The receive function is a non-blocking read that immediately either returns a message or nothing.
+ * Equivalent to StackTimeout_MicroSeconds(0)
+ */
+#define CCNxStackTimeout_Immediate (& (uint64_t) { 0 })
+
+/*
+ * @def CCNxStackTimeout_MicroSeconds
+ * The receive function is a blocking read that either waits no longer than the specified number of microseconds or a message,
+ * whichever comes first.
+ */
+#define CCNxStackTimeout_MicroSeconds(_usec_) (& (uint64_t) { _usec_ })
+
+
+/**
+ * Initialize transport. Creates a thread of execution,
+ * you only need one of these.
+ *
+ * You can only have one of these. Multiple calls return a
+ * reference to the existing one (if same type) or an error.
+ *
+ * NULL means error.
+ */
+TransportContext *Transport_Create(TransportTypes type);
+
+/**
+ * Open a descriptor. You may use a select(2) or poll(2) on it, but
+ * you must only use Transport_{Send, Recv, Close} to modify it.
+ *
+ * All transport operations are non-blocking.
+ *
+ * Transport will take ownership of the transportConfig and destroy it and
+ * everyting contained in it.
+ *
+ * Generate the configuration based on your stacks configuration
+ * methods. For RTA, they are in transport_rta/config/.
+ *
+ * @param [in] transportConfig the transport configuration object
+ *
+ * @return the newly opened descriptor
+ *
+ * @see Transport_Close
+ */
+int Transport_Open(CCNxTransportConfig *transportConfig);
+
+/**
+ * Send a `CCNxMetaMessage` to the transport. The CCNxMetaMessage instance is acquired by
+ * the stack and can be released by the caller immediately after sending if desired.
+ *
+ * The CCNxMetaMessage may be a PARCJSON object to modify USER stack parameters.
+ *
+ * @param [in] desc the file descriptor (e.g. one end of a socket) in to which to write he CCNxMetaMessage.
+ * @param [in] msg_in A CCNxMetaMessage instance to send.
+ *
+ * @return 0 if the message was succesfully sent.
+ * @return -1 and sets errno, otherwise. errno will be set to EWOULDBLOCK if it would block.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *msg = ccnxMetaMessage_CreateFromContentObject(contentObject);
+ *
+ * int status = Transport_Send(desc, msg);
+ *
+ * ccnxMetaMessage_Release(&msg);
+ * }
+ * @endcode
+ *
+ * @see ccnxMetaMessage_Release
+ */
+int Transport_Send(int desc, CCNxMetaMessage *msg_in);
+
+/**
+ * Receive a `CCNxMetaMessage` from the transport. The caller is responsible
+ * for calling {@link ccnxMetaMessage_Release} on the message, if successful.
+ *
+ * @param [in] desc the file descriptor (e.g. one end of a socket) from which to read the CCNxMetaMessage.
+ * @param [in] msg_in A CCNxMetaMessage instance to send.
+ *
+ * @return 0 if the message was succesfully sent.
+ * @return -1 and sets errno, otherwise. errno will be set to EWOULDBLOCK if the call would block
+ * or if SO_RCVTIMEO is exceeded on the underlying socket.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *msg;
+ * int status = Transport_Recv(desc, &msg);
+ *
+ * if (status == 0) {
+ * // do things
+ *
+ * ccnxMetaMessage_Release(&msg);
+ * }
+ * }
+ * @endcode
+ *
+ * @see ccnxMetaMessage_Release
+ */
+TransportIOStatus Transport_Recv(int desc, CCNxMetaMessage **msg_out);
+
+/**
+ * Closes a descriptor. Close is immediate, any pending data is lost.
+ *
+ * @param [in] desc the descriptor to close
+ *
+ * @return 0 on success (the descriptor exists and was open)
+ *
+ * @see Transport_Open
+ */
+int Transport_Close(int desc);
+
+/**
+ * Pass a transport-specific command to the underlying framework.
+ * It must be in a "TransportTypes" format that your chosen
+ * transport understands.
+ */
+int Transport_PassCommand(void *stackCommand);
+
+/**
+ * Destroy a TransportContext instance. Shuts done all descriptors and any pending data is lost.
+ *
+ * @param [in] ctxP A pointer to a pointer to the TransportContext instance to release.
+ */
+void Transport_Destroy(TransportContext **ctxP);
+#endif // CCNX_TRANSPORT_H
diff --git a/libccnx-transport-rta/ccnx/transport/common/transport_Message.c b/libccnx-transport-rta/ccnx/transport/common/transport_Message.c
new file mode 100644
index 00000000..1a79ace2
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/transport_Message.c
@@ -0,0 +1,198 @@
+/*
+ * 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 <strings.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <ccnx/transport/common/transport.h>
+#include <ccnx/transport/common/transport_private.h>
+#include <ccnx/transport/common/transport_Message.h>
+
+#define DEBUG_OUTPUT 0
+
+struct transport_message {
+ CCNxTlvDictionary *dictionary;
+ TransportMessage_Free *freefunc;
+ void *info;
+
+ struct timeval creationTime;
+};
+
+static size_t _transport_messages_created = 0;
+static size_t _transport_messages_destroyed = 0;
+
+static void
+_transportMessage_GetTimeOfDay(struct timeval *outputTime)
+{
+#ifdef DEBUG
+ // if in debug mode, time messages
+ gettimeofday(outputTime, NULL);
+#else
+ *outputTime = (struct timeval) { 0, 0 };
+#endif
+}
+
+TransportMessage *
+transportMessage_CreateFromDictionary(CCNxTlvDictionary *dictionary)
+{
+ assertNotNull(dictionary, "Cannot create TransportMessage from NULL Dictionary");
+ if (dictionary == NULL) {
+ return NULL;
+ }
+
+ TransportMessage *tm = parcMemory_AllocateAndClear(sizeof(TransportMessage));
+
+ if (tm != NULL) {
+ tm->dictionary = ccnxTlvDictionary_Acquire(dictionary);
+
+ _transportMessage_GetTimeOfDay(&tm->creationTime);
+
+ _transport_messages_created++;
+
+ if (DEBUG_OUTPUT) {
+ printf("%-35s allocs %zu destroys %zu pointer %p dict %p\n",
+ __func__,
+ _transport_messages_created,
+ _transport_messages_destroyed,
+ (void *) tm,
+ (void *) dictionary);
+ }
+ }
+
+ return tm;
+}
+
+CCNxTlvDictionary *
+transportMessage_GetDictionary(TransportMessage *tm)
+{
+ assertNotNull(tm, "TransportMessage_GetWireMessage called on NULL transport message");
+ return tm->dictionary;
+}
+
+bool
+transportMessage_isValid(const TransportMessage *message)
+{
+ bool result = false;
+ if (message != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+void
+transportMessage_AssertValid(const TransportMessage *message)
+{
+ assertTrue(transportMessage_isValid(message), "TransportMessage @ %p is invalid.", (void *) message);
+}
+
+/*
+ * Frees the TransportMessage wrapper, but user is responsible
+ * for destroying the inner pieces.
+ */
+static void
+_transportMessage_Destroy(TransportMessage **msgPtr)
+{
+ assertNotNull(msgPtr, "TransportMessage_Destroy called on NULL transport message pointer");
+ if (msgPtr != NULL) {
+ TransportMessage *msg = *msgPtr;
+ transportMessage_OptionalAssertValid(msg);
+
+ _transport_messages_destroyed++;
+
+ if (DEBUG_OUTPUT) {
+ printf("%-35s allocs %zu destroys %zu pointer %p\n",
+ __func__,
+ _transport_messages_created,
+ _transport_messages_destroyed,
+ (void *) msg);
+ }
+
+ if (msg->freefunc != NULL) {
+ msg->freefunc(&msg->info);
+ }
+
+ parcMemory_Deallocate((void **) &msg);
+ *msgPtr = NULL;
+ }
+}
+
+void
+transportMessage_Destroy(TransportMessage **tmPtr)
+{
+ TransportMessage *tm = *tmPtr;
+ assertNotNull(tmPtr, "called with NULL transport message double pointer");
+
+ assertNotNull(tm, "called with NULL transport message dereference");
+
+ if (tm->dictionary != NULL) {
+ ccnxTlvDictionary_Release(&tm->dictionary);
+ tm->dictionary = NULL;
+ }
+
+ _transportMessage_Destroy(tmPtr);
+}
+
+/*
+ * Add some stack payload to a transport message. Will not be freed.
+ */
+void
+transportMessage_SetInfo(TransportMessage *tm, void *info, TransportMessage_Free *freefunc)
+{
+ assertNotNull(tm, "%s called with NULL transport message", __func__);
+ tm->info = info;
+ tm->freefunc = freefunc;
+}
+
+void *
+transportMessage_GetInfo(const TransportMessage *tm)
+{
+ assertNotNull(tm, "%s called with NULL transport message", __func__);
+ return tm->info;
+}
+
+
+struct timeval
+transportMessage_GetDelay(const TransportMessage *tm)
+{
+ struct timeval now;
+ _transportMessage_GetTimeOfDay(&now);
+ timersub(&now, &tm->creationTime, &now);
+ return now;
+}
+
+bool
+transportMessage_IsControl(const TransportMessage *tm)
+{
+ return ccnxTlvDictionary_IsControl(tm->dictionary);
+}
+
+bool
+transportMessage_IsInterest(const TransportMessage *tm)
+{
+ return ccnxTlvDictionary_IsInterest(tm->dictionary);
+}
+
+bool
+transportMessage_IsContentObject(const TransportMessage *tm)
+{
+ return ccnxTlvDictionary_IsContentObject(tm->dictionary);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/common/transport_Message.h b/libccnx-transport-rta/ccnx/transport/common/transport_Message.h
new file mode 100644
index 00000000..5f79fc3b
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/transport_Message.h
@@ -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.
+ */
+
+/**
+ * @file transport_Message.h
+ * @brief <#Brief Description#>
+ *
+ * NOTE: TransportMessage is being phased out for the CCNxTlvDictionary
+ *
+ */
+#ifndef Libccnx_transport_Message_h
+#define Libccnx_transport_Message_h
+
+#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+struct transport_message;
+/**
+ *
+ * @see TransportMessage_CreateFromCcnxMessage
+ * @see TransportMessage_CreateFromMessage
+ */
+typedef struct transport_message TransportMessage;
+
+/**
+ * Stores a reference to the given dictionary
+ *
+ * The caller is responsible for releasing 'dictionary' as the transport message stores its own reference.
+ *
+ * @param [in] dictionary A pointer to a valid `CCNxTlvDictionary`
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+TransportMessage *transportMessage_CreateFromDictionary(CCNxTlvDictionary *dictionary);
+
+bool transportMessage_isValid(const TransportMessage *message);
+
+#ifdef TransportLibrary_DISABLE_VALIDATION
+# define transportMessage_OptionalAssertValid(_instance_)
+#else
+# define transportMessage_OptionalAssertValid(_instance_) transportMessage_AssertValid(_instance_)
+#endif
+/**
+ * Assert that the given `TransportMessage` instance is valid.
+ *
+ * @param [in] message A pointer to a valid TransportMessage instance.
+ *
+ * Example:
+ * @code
+ * {
+ * TransportMessage *a = transportMessage_CreateFromDictionary(dictionary);
+ *
+ * transportMessage_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * transportMessage_Release(&b);
+ * }
+ * @endcode
+ */
+void transportMessage_AssertValid(const TransportMessage *message);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxTlvDictionary *transportMessage_GetDictionary(TransportMessage *tm);
+
+/**
+ * Destroy the transport message and everything inside it
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void transportMessage_Destroy(TransportMessage **tmPtr);
+
+typedef void (TransportMessage_Free)(void **);
+
+/**
+ * <#One Line Description#>
+ *
+ * Add some stack payload to a transport message.
+ * Will not be freed.
+ * This is typically used to put a pointer to the RtaConnection in the message.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void transportMessage_SetInfo(TransportMessage *tm, void *info, TransportMessage_Free *freefunc);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void *transportMessage_GetInfo(const TransportMessage *tm);
+
+bool transportMessage_IsControl(const TransportMessage *tm);
+bool transportMessage_IsInterest(const TransportMessage *tm);
+bool transportMessage_IsContentObject(const TransportMessage *tm);
+
+/**
+ * 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().
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+struct timeval transportMessage_GetDelay(const TransportMessage *tm);
+#endif // Libccnx_transport_Message_h
diff --git a/libccnx-transport-rta/ccnx/transport/common/transport_MetaMessage.c b/libccnx-transport-rta/ccnx/transport/common/transport_MetaMessage.c
new file mode 100644
index 00000000..a455e7ac
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/transport_MetaMessage.c
@@ -0,0 +1,193 @@
+/*
+ * 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/transport/common/transport_MetaMessage.h>
+#include <ccnx/common/codec/ccnxCodec_TlvPacket.h>
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+#include <ccnx/common/ccnx_Manifest.h>
+
+CCNxMetaMessage *
+ccnxMetaMessage_CreateFromInterest(const CCNxInterest *interest)
+{
+ return ccnxMetaMessage_Acquire((CCNxMetaMessage *) interest);
+}
+
+CCNxMetaMessage *
+ccnxMetaMessage_CreateFromContentObject(const CCNxContentObject *contentObject)
+{
+ return ccnxMetaMessage_Acquire((CCNxMetaMessage *) contentObject);
+}
+
+CCNxMetaMessage *
+ccnxMetaMessage_CreateFromControl(const CCNxControl *control)
+{
+ return ccnxMetaMessage_Acquire((CCNxMetaMessage *) control);
+}
+
+CCNxMetaMessage *
+ccnxMetaMessage_CreateFromManifest(const CCNxManifest *manifest)
+{
+ return ccnxMetaMessage_Acquire((CCNxMetaMessage *) manifest);
+}
+
+
+CCNxContentObject *
+ccnxMetaMessage_GetContentObject(const CCNxMetaMessage *message)
+{
+ return (CCNxContentObject *) message;
+}
+
+CCNxInterest *
+ccnxMetaMessage_GetInterest(const CCNxMetaMessage *message)
+{
+ return (CCNxInterest *) message;
+}
+
+CCNxInterestReturn *
+ccnxMetaMessage_GetInterestReturn(const CCNxMetaMessage *message)
+{
+ return (CCNxInterestReturn *) message;
+}
+
+CCNxControl *
+ccnxMetaMessage_GetControl(const CCNxMetaMessage *message)
+{
+ return (CCNxControl *) message;
+}
+
+CCNxManifest *
+ccnxMetaMessage_GetManifest(const CCNxMetaMessage *message)
+{
+ return (CCNxManifest *) message;
+}
+
+CCNxMetaMessage *
+ccnxMetaMessage_Acquire(const CCNxMetaMessage *message)
+{
+ return ccnxTlvDictionary_Acquire(message);
+}
+
+void
+ccnxMetaMessage_Release(CCNxMetaMessage **messagePtr)
+{
+ ccnxTlvDictionary_Release(messagePtr);
+}
+
+void
+ccnxMetaMessage_Display(const CCNxMetaMessage *message, int indentation)
+{
+ ccnxTlvDictionary_Display(message, indentation);
+}
+
+bool
+ccnxMetaMessage_IsContentObject(const CCNxMetaMessage *message)
+{
+ return ccnxTlvDictionary_IsContentObject(message);
+}
+
+bool
+ccnxMetaMessage_IsInterest(const CCNxMetaMessage *message)
+{
+ return ccnxTlvDictionary_IsInterest(message);
+}
+
+bool
+ccnxMetaMessage_IsInterestReturn(const CCNxMetaMessage *message)
+{
+ return ccnxTlvDictionary_IsInterestReturn(message);
+}
+
+bool
+ccnxMetaMessage_IsControl(const CCNxMetaMessage *message)
+{
+ return ccnxTlvDictionary_IsControl(message);
+}
+
+bool
+ccnxMetaMessage_IsManifest(const CCNxMetaMessage *message)
+{
+ return ccnxTlvDictionary_IsManifest(message);
+}
+
+/**
+ * Given an iovec encoded version of a TlvDictionary, which is what we get when we call ccnxCodecTlvPacket_DictionaryEncode(),
+ * linearize it into a PARCBuffer so we can treat it as a PARCBuffer.
+ */
+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;
+}
+
+CCNxMetaMessage *
+ccnxMetaMessage_CreateFromWireFormatBuffer(PARCBuffer *rawMessage)
+{
+ CCNxMetaMessage *result = NULL;
+
+ CCNxWireFormatMessage *message = ccnxWireFormatMessage_Create(rawMessage);
+
+ if (message != NULL) {
+ // Get the dictionary from the ccnxWireFormatMessage.
+ CCNxTlvDictionary *dictionary = ccnxWireFormatMessage_GetDictionary(message);
+
+ // We have a partially unpacked dictionary now, but we need to more fully unpack it for our processing.
+ bool success = ccnxCodecTlvPacket_BufferDecode(rawMessage, dictionary);
+
+ if (success) {
+ result = (CCNxMetaMessage *) dictionary;
+ } else {
+ ccnxWireFormatMessage_Release(&message);
+ result = NULL;
+ }
+ }
+
+ return result;
+}
+
+PARCBuffer *
+ccnxMetaMessage_CreateWireFormatBuffer(CCNxMetaMessage *message, PARCSigner *signer)
+{
+ CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(message, signer);
+
+ // iovec has the wireformat version of 'interest' now.
+
+ PARCBuffer *result = _iovecToParcBuffer(iovec);
+
+ ccnxCodecNetworkBufferIoVec_Release(&iovec);
+
+ return result;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/common/transport_MetaMessage.h b/libccnx-transport-rta/ccnx/transport/common/transport_MetaMessage.h
new file mode 100644
index 00000000..f7dda45c
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/transport_MetaMessage.h
@@ -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.
+ */
+
+/**
+ * @file ccnx_MetaMessage.h
+ * @brief A CCNx message suitable for sending through the CCNx Portal API.
+ *
+ * A CCNxMetaMessage encapsulates a CCN Interest, ContentObject, or Control message, and can
+ * be read from and written to the CCNx Portal API.
+ *
+ */
+#ifndef libccnx_ccnx_MetaMessage_h
+#define libccnx_ccnx_MetaMessage_h
+
+#include <ccnx/common/ccnx_Interest.h>
+#include <ccnx/common/ccnx_InterestReturn.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+#include <ccnx/common/ccnx_Manifest.h>
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+#include <ccnx/api/control/cpi_ControlMessage.h>
+
+/**
+ * @typedef CCNxMetaMessage
+ * @brief A CCNxMetaMessage encapsulates a CCN Interest, ContentObject, or Control message.
+ */
+typedef CCNxTlvDictionary CCNxMetaMessage;
+
+
+/**
+ * Create a `CCNxMetaMessage` instance containing the given {@link CCNxInterest}.
+ *
+ * A new reference to the `CCNxInterest` is created.
+ *
+ * @param [in] interest A pointer to a valid `CCNxInterest` instance.
+ *
+ * @return NULL The `CCNxInterest` is not valid, or memory could not be allocated.
+ * @return non-NULL A pointer to a `CCNxMetaMessage` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+ * }
+ * @endcode
+ */
+CCNxMetaMessage *ccnxMetaMessage_CreateFromInterest(const CCNxInterest *interest);
+
+/**
+ * Create a `CCNxMetaMessage` instance containing the given {@link CCNxContentObject}.
+ *
+ * A new reference to the `CCNxContentObject` is created.
+ *
+ * @param [in] contentObject A pointer to a valid `CCNxContentObject` instance.
+ *
+ * @return NULL The `CCNxContentObject` is not valid, or memory could not be allocated.
+ * @return non-NULL A pointer to a `CCNxMetaMessage` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxMetaMessage_CreateFromContentObject(contentObject);
+ * }
+ * @endcode
+ */
+CCNxMetaMessage *ccnxMetaMessage_CreateFromContentObject(const CCNxContentObject *contentObject);
+
+/**
+ * Create a `CCNxMetaMessage` instance containing the given {@link CCNxControl}.
+ *
+ * A new reference to the `CCNxControl` is created.
+ *
+ * @param [in] control A pointer to a valid `CCNxControl` instance.
+ *
+ * @return NULL The `CCNxControl` is not valid, or memory could not be allocated.
+ * @return non-NULL A pointer to a `CCNxMetaMessage` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxMetaMessage_CreateFromControl(control);
+ * }
+ * @endcode
+ */
+CCNxMetaMessage *ccnxMetaMessage_CreateFromControl(const CCNxControl *control);
+
+/**
+ * Create a `CCNxMetaMessage` instance containing the given {@link CCNxManifest}.
+ *
+ * A new reference to the `CCNxManifest` is created.
+ *
+ * @param [in] control A pointer to a valid `CCNxManifest` instance.
+ *
+ * @return NULL The `CCNxManifest` is not valid, or memory could not be allocated.
+ * @return non-NULL A pointer to a `CCNxMetaMessage` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxMetaMessage_CreateFromManifest(manifest);
+ * }
+ * @endcode
+ */
+CCNxMetaMessage *ccnxMetaMessage_CreateFromManifest(const CCNxManifest *manifest);
+
+/**
+ * Print a human readable representation of the given `CCNxMetaMessage` instance.
+ *
+ * @param [in] message A pointer to the `CCNxMetaMessage` to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(...);
+ *
+ * ccnxMetaMessage_Display(message, 0);
+ *
+ * ccnxMetaMessage_Release(&message);
+ * }
+ * @endcode
+ *
+ */
+void ccnxMetaMessage_Display(const CCNxMetaMessage *message, int indentation);
+
+/**
+ * Increase the number of references to a `CCNxMetaMessage`.
+ *
+ * Note that new `CCNxMetaMessage` is not created,
+ * only that the given `CCNxMetaMessage` reference count is incremented.
+ * Discard the reference by invoking {@link ccnxMetaMessage_Release}().
+ *
+ * @param [in] instance A pointer to a `CCNxMetaMessage` instance.
+ * @return The input @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ * CCNxMetaMessage *messageReference = ccnxMetaMessage_Acquire(message);
+ *
+ * ccnxMetaMessage_Release(&message);
+ * ccnxMetaMessage_Release(&messageReference);
+ * }
+ * @endcode
+ * @see `ccnxMetaMessage_Release`
+ */
+CCNxMetaMessage *ccnxMetaMessage_Acquire(const CCNxMetaMessage *instance);
+
+/**
+ * Determine whether a specified `CCNxMetaMessage` instance encapsulates an {@link CCNxInterest}.
+ *
+ * Returns `true` if the underlying message is a `CCNxInterest`.
+ *
+ * @param [in] message A pointer to a `CCNxMetaMessage` instance.
+ *
+ * @return `true` If the underlying message is a `CCNxInterest`.
+ * @return `false` If the underlying message is not a `CCNxInterest`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ *
+ * if (ccnxMetaMessage_IsInterest(message)) {
+ * CCNxInterest *interest = ccnxMetaMessage_GetInterest(message);
+ * ...
+ * ccnxInterest_Release(&interest);
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * }
+ * @endcode
+ * @see CCNxInterest
+ */
+bool ccnxMetaMessage_IsInterest(const CCNxMetaMessage *message);
+
+/**
+ * Determine whether a specified `CCNxMetaMessage` instance encapsulates an {@link CCNxInterestReturn}.
+ *
+ * Returns `true` if the underlying message is a `CCNxInterestReturn`.
+ *
+ * @param [in] message A pointer to a `CCNxMetaMessage` instance.
+ *
+ * @return `true` If the underlying message is a `CCNxInterestReturn`.
+ * @return `false` If the underlying message is not a `CCNxInterestReturn`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ *
+ * if (ccnxMetaMessage_IsInterestReturn(message)) {
+ * CCNxInterestReturn *interestReturn = ccnxMetaMessage_GetInterestReturn(message);
+ *
+ * ...
+ * ccnxInterestReturn_Release(&interestReturn);
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * }
+ * @endcode
+ * @see CCNxInterestReturn
+ */
+bool ccnxMetaMessage_IsInterestReturn(const CCNxMetaMessage *message);
+
+/**
+ * Determine whether a specified `CCNxMetaMessage` instance encapsulates a {@link CCNxContentObject}.
+ *
+ * Returns true if the underlying message is a `CCNxContentObject`.
+ *
+ * @param [in] message A pointer to a `CCNxMetaMessage` instance.
+ *
+ * @return `true` If the underlying message is a `CCNxContentObject`.
+ * @return `false` If the underlying message is not a `CCNxContentObject`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ *
+ * if (ccnxMetaMessage_IsContentObject(message)) {
+ * CCNxContentObject *contentObject = ccnxMetaMessage_GetContentObject(message);
+ * ...
+ * ccnxContentObject_Release(&contentObject);
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * }
+ * @endcode
+ * @see `CCNxContentObject`
+ */
+bool ccnxMetaMessage_IsContentObject(const CCNxMetaMessage *message);
+
+/**
+ * Determine whether a specified `CCNxMetaMessage` instance encapsulates a {@link CCNxControl}.
+ *
+ * Returns true if the underlying message is a `CCNxControl`.
+ *
+ * @param [in] message A pointer to a `CCNxMetaMessage` instance.
+ *
+ * @return `true` If the underlying message is a `CCNxControl`.
+ * @return `false` If the underlying message is not a `CCNxControl`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ *
+ * if (ccnxMetaMessage_IsControl(message)) {
+ * CCNxControl *control = ccnxMetaMessage_GetControl(message);
+ * ...
+ * ccnxControl_Release(&control);
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * }
+ * @endcode
+ * @see `CCNxControl`
+ */
+bool ccnxMetaMessage_IsControl(const CCNxMetaMessage *message);
+
+/**
+ * Determine whether a specified `CCNxMetaMessage` instance encapsulates a {@link CCNxManifest}.
+ *
+ * Returns true if the underlying message is a `CCNxManifest`.
+ *
+ * @param [in] message A pointer to a `CCNxMetaMessage` instance.
+ *
+ * @return `true` If the underlying message is a `CCNxManifest`.
+ * @return `false` If the underlying message is not a `CCNxManifest`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ *
+ * if (ccnxMetaMessage_IsManifest(message)) {
+ * CCNxManifest *control = ccnxMetaMessage_GetManifest(message);
+ * ...
+ * ccnxManifest_Release(&manifest);
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * }
+ * @endcode
+ * @see `CCNxManifest`
+ */
+bool ccnxMetaMessage_IsManifest(const CCNxMetaMessage *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] messagePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ * CCNxMetaMessage *messageReference = ccnxMetaMessage_Acquire(message);
+ *
+ * ccnxMetaMessage_Release(&message);
+ * ccnxMetaMessage_Release(&messageReference);
+ * }
+ * @endcode
+ * @see {@link ccnxMetaMessage_Acquire}
+ */
+void ccnxMetaMessage_Release(CCNxMetaMessage **messagePtr);
+
+/**
+ * Return a new {@link CCNxContentObject} instance created from the `CCNxMetaMessage`.
+ *
+ * The newly created `CCNxContentObject` instance must eventually be released by calling {@link ccnxContentObject_Release}().
+ *
+ * @param [in] message A pointer to a `CCNxMetaMessage` instance.
+ *
+ * @return A new `CCNxContentObject` instance, which must eventually be released by calling `ccnxContentObject_Release()`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ *
+ * if (ccnxMetaMessage_IsContentObject(message)) {
+ * CCNxContentObject *contentObject = ccnxMetaMessage_GetContentObject(message);
+ * ...
+ * ccnxContentObject_Release(&contentObject);
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * }
+ * @endcode
+ *
+ * @see `ccnxContentObject_Release`
+ * @see {@link ccnxMetaMessage_IsContentObject}
+ */
+CCNxContentObject *ccnxMetaMessage_GetContentObject(const CCNxMetaMessage *message);
+
+/**
+ * Return a new {@link CCNxInterest} instance created from the `CCNxMetaMessage`.
+ *
+ * The newly created `CCNxInterest}\` instance must eventually be released by calling {@link ccnxInterest_Release}().
+ *
+ * @param [in] message A pointer to a `CCNxMetaMessage` instance.
+ *
+ * @return A new `CCNxInterest` instance, which must eventually be released by calling `ccnxInterest_Release()`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ *
+ * if (ccnxMetaMessage_IsInterest(message)) {
+ * CCNxInterest *interest = ccnxMetaMessage_GetInterest(message);
+ * ...
+ * ccnxInterest_Release(&interest);
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * }
+ * @endcode
+ *
+ * @see `ccnxInterest_Release`
+ * @see {@link ccnxMetaMessage_IsInterest}
+ */
+CCNxInterest *ccnxMetaMessage_GetInterest(const CCNxMetaMessage *message);
+
+/**
+ * Return a new {@link CCNxInterestReturn} instance created from the `CCNxMetaMessage`.
+ *
+ * The newly created `CCNxInterestReturn}\` instance must eventually be released by calling {@link ccnxInterest_Release}().
+ *
+ * @param [in] message A pointer to a `CCNxMetaMessage` instance.
+ *
+ * @return A new `CCNxInterest` instance, which must eventually be released by calling `ccnxInterestReturn_Release()`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ *
+ * if (ccnxMetaMessage_IsInterestReturn(message)) {
+ * CCNxInterestReturn *interestReturn = ccnxMetaMessage_GetInterestReturn(message);
+ *
+ * ...
+ * ccnxInterestReturn_Release(&interestReturn);
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * }
+ * @endcode
+ *
+ * @see `ccnxInterest_Release`
+ * @see {@link ccnxMetaMessage_IsInterest}
+ */
+CCNxInterest *ccnxMetaMessage_GetInterestReturn(const CCNxMetaMessage *message);
+
+/**
+ * Return a new {@link CCNxControl} instance created from the `CCNxMetaMessage`.
+ *
+ * The newly created `CCNxControl` instance must eventually be released by calling {@link ccnxControl_Release}().
+ *
+ * @param [in] message A pointer to a `CCNxMetaMessage` instance.
+ *
+ * @return A new `CCNxControl` instance, which must eventually be released by calling `ccnxControl_Release()`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ *
+ * if (ccnxMetaMessage_IsControl(message)) {
+ * CCNxControl *control = ccnxMetaMessage_GetControl(message);
+ * ...
+ * ccnxControl_Release(&control);
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * }
+ * @endcode
+ *
+ * @see `ccnxControl_Release`
+ * @see {@link ccnxMetaMessage_IsControl}
+ */
+CCNxControl *ccnxMetaMessage_GetControl(const CCNxMetaMessage *message);
+
+/**
+ * Return a new {@link CCNxManifest} instance created from the `CCNxMetaMessage`.
+ *
+ * The newly created `CCNxManifest` instance must eventually be released by calling {@link ccnxManifest_Release}().
+ *
+ * @param [in] message A pointer to a `CCNxMetaMessage` instance.
+ *
+ * @return A new `CCNxManifest` instance, which must eventually be released by calling `ccnxManifest_Release()`.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxMetaMessage *message = ccnxPortal_Receive(portal, CCNxStackTimeout_Never);
+ *
+ * if (ccnxMetaMessage_IsManifest(message)) {
+ * CCNxManifest *manifest = ccnxMetaMessage_GetManifest(message);
+ * ...
+ * ccnxManifest_Release(&manifest);
+ * }
+ *
+ * ccnxMetaMessage_Release(&message);
+ * }
+ * @endcode
+ *
+ * @see {@link ccnxManifest_Release}
+ * @see {@link ccnxMetaMessage_IsManifest}
+ */
+CCNxManifest *ccnxMetaMessage_GetManifest(const CCNxMetaMessage *message);
+
+/**
+ * Return a new {@link CCNxMetaMessage} instance created from a wire format message
+ *
+ * The newly created `CCNxMetaMessage` instance must eventually be released by calling {@link CCNxMetaMessage_Release}().
+ *
+ * @param [in] message A pointer to a `PARCBuffer` instance containing a wire format message.
+ *
+ * @return A new `CCNxMetaMessage` instance, which must eventually be released by calling `ccnxMetaMessage_Release()`.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ *
+ */
+CCNxMetaMessage *ccnxMetaMessage_CreateFromWireFormatBuffer(PARCBuffer *rawMessage);
+
+/**
+ * Return a new {@link PARCBuffer} instance containing an encodeded wire format message created
+ * from the source `CCNxMetaMessage`.
+ *
+ * The newly created `PARCBuffer` instance must eventually be released by calling {@link parcBuffer_Release}().
+ *
+ * @param [in] message A pointer to a `CCNxMetaMessage` instance.
+ * @param [in] signer A pointer to a `PARCSigner` instance.
+ *
+ * @return A new `PARCBuffer` instance, which must eventually be released by calling `parcBuffer_Release()`.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ *
+ */
+PARCBuffer *ccnxMetaMessage_CreateWireFormatBuffer(CCNxMetaMessage *message, PARCSigner *signer);
+
+#endif // libccnx_ccnx_MetaMessage_h
diff --git a/libccnx-transport-rta/ccnx/transport/common/transport_Stack.c b/libccnx-transport-rta/ccnx/transport/common/transport_Stack.c
new file mode 100644
index 00000000..1d529710
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/transport_Stack.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 <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <transport_Stack.h>
+
+struct TransportStack {
+ int topFD;
+ int bottomFD;
+};
+
+static void
+_transportStack_Finalize(TransportStack **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a TransportStack pointer.");
+ TransportStack *instance = *instancePtr;
+
+ transportStack_OptionalAssertValid(instance);
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(transportStack, TransportStack);
+
+parcObject_ImplementRelease(transportStack, TransportStack);
+
+parcObject_ExtendPARCObject(TransportStack, _transportStack_Finalize, transportStack_Copy, transportStack_ToString, transportStack_Equals, transportStack_Compare, transportStack_HashCode, transportStack_ToJSON);
+
+
+void
+transportStack_AssertValid(const TransportStack *instance)
+{
+ assertTrue(transportStack_IsValid(instance),
+ "TransportStack is not valid.");
+}
+
+
+TransportStack *
+transportStack_Create(void)
+{
+ TransportStack *result = parcObject_CreateInstance(TransportStack);
+
+ return result;
+}
+
+int
+transportStack_Compare(const TransportStack *instance, const TransportStack *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+TransportStack *
+transportStack_Copy(const TransportStack *original)
+{
+ TransportStack *result = NULL;
+
+ return result;
+}
+
+void
+transportStack_Display(const TransportStack *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "TransportStack@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+transportStack_Equals(const TransportStack *x, const TransportStack *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ /* perform instance specific equality tests here. */
+ }
+
+ return result;
+}
+
+PARCHashCode
+transportStack_HashCode(const TransportStack *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+transportStack_IsValid(const TransportStack *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+transportStack_ToJSON(const TransportStack *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ return result;
+}
+
+char *
+transportStack_ToString(const TransportStack *instance)
+{
+ char *result = parcMemory_Format("TransportStack@%p\n", instance);
+
+ return result;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/common/transport_Stack.h b/libccnx-transport-rta/ccnx/transport/common/transport_Stack.h
new file mode 100644
index 00000000..6b38c2a5
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/transport_Stack.h
@@ -0,0 +1,354 @@
+/*
+ * 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 transport_Stack.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef libccnx_ccnx_transport_Stack
+#define libccnx_ccnx_transport_Stack
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+struct TransportStack;
+typedef struct TransportStack TransportStack;
+
+/**
+ * Increase the number of references to a `TransportStack` instance.
+ *
+ * Note that new `TransportStack` is not created,
+ * only that the given `TransportStack` reference count is incremented.
+ * Discard the reference by invoking `transportStack_Release`.
+ *
+ * @param [in] instance A pointer to a valid TransportStack instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * TransportStack *a = transportStack_Create();
+ *
+ * TransportStack *b = transportStack_Acquire();
+ *
+ * transportStack_Release(&a);
+ * transportStack_Release(&b);
+ * }
+ * @endcode
+ */
+TransportStack *transportStack_Acquire(const TransportStack *instance);
+
+#ifdef LIBRTA_DISABLE_VALIDATION
+# define transportStack_OptionalAssertValid(_instance_)
+#else
+# define transportStack_OptionalAssertValid(_instance_) transportStack_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `TransportStack` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid TransportStack instance.
+ *
+ * Example:
+ * @code
+ * {
+ * TransportStack *a = transportStack_Create();
+ *
+ * transportStack_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * transportStack_Release(&b);
+ * }
+ * @endcode
+ */
+void transportStack_AssertValid(const TransportStack *instance);
+
+/**
+ * Create an instance of TransportStack
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid TransportStack instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * TransportStack *a = transportStack_Create();
+ *
+ * transportStack_Release(&a);
+ * }
+ * @endcode
+ */
+TransportStack *transportStack_Create(void);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid TransportStack instance.
+ * @param [in] other A pointer to a valid TransportStack instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * TransportStack *a = transportStack_Create();
+ * TransportStack *b = transportStack_Create();
+ *
+ * if (transportStack_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * transportStack_Release(&a);
+ * transportStack_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see transportStack_Equals
+ */
+int transportStack_Compare(const TransportStack *instance, const TransportStack *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid TransportStack instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `TransportStack` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * TransportStack *a = transportStack_Create();
+ *
+ * TransportStack *copy = transportStack_Copy(&b);
+ *
+ * transportStack_Release(&b);
+ * transportStack_Release(&copy);
+ * }
+ * @endcode
+ */
+TransportStack *transportStack_Copy(const TransportStack *original);
+
+/**
+ * Print a human readable representation of the given `TransportStack`.
+ *
+ * @param [in] instance A pointer to a valid TransportStack instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * TransportStack *a = transportStack_Create();
+ *
+ * transportStack_Display(a, 0);
+ *
+ * transportStack_Release(&a);
+ * }
+ * @endcode
+ */
+void transportStack_Display(const TransportStack *instance, int indentation);
+
+/**
+ * Determine if two `TransportStack` instances are equal.
+ *
+ * The following equivalence relations on non-null `TransportStack` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `transportStack_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `transportStack_Equals(x, y)` must return true if and only if
+ * `transportStack_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `transportStack_Equals(x, y)` returns true and
+ * `transportStack_Equals(y, z)` returns true,
+ * then `transportStack_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `transportStack_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `transportStack_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid TransportStack instance.
+ * @param [in] y A pointer to a valid TransportStack instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * TransportStack *a = transportStack_Create();
+ * TransportStack *b = transportStack_Create();
+ *
+ * if (transportStack_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * transportStack_Release(&a);
+ * transportStack_Release(&b);
+ * }
+ * @endcode
+ * @see transportStack_HashCode
+ */
+bool transportStack_Equals(const TransportStack *x, const TransportStack *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the 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 {@link transportStack_Equals} method,
+ * then calling the {@link transportStack_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link transportStack_Equals} function,
+ * then calling the `transportStack_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid TransportStack instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * TransportStack *a = transportStack_Create();
+ *
+ * PARCHashCode hashValue = transportStack_HashCode(buffer);
+ * transportStack_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode transportStack_HashCode(const TransportStack *instance);
+
+/**
+ * Determine if an instance of `TransportStack` 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] instance A pointer to a valid TransportStack instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * TransportStack *a = transportStack_Create();
+ *
+ * if (transportStack_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * transportStack_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool transportStack_IsValid(const TransportStack *instance);
+
+/**
+ * Release a previously acquired reference to the given `TransportStack` 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] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * TransportStack *a = transportStack_Create();
+ *
+ * transportStack_Release(&a);
+ * }
+ * @endcode
+ */
+void transportStack_Release(TransportStack **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid TransportStack instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * TransportStack *a = transportStack_Create();
+ *
+ * PARCJSON *json = transportStack_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * transportStack_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *transportStack_ToJSON(const TransportStack *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `TransportStack`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid TransportStack instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * TransportStack *a = transportStack_Create();
+ *
+ * char *string = transportStack_ToString(a);
+ *
+ * transportStack_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see transportStack_Display
+ */
+char *transportStack_ToString(const TransportStack *instance);
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/common/transport_private.h b/libccnx-transport-rta/ccnx/transport/common/transport_private.h
new file mode 100644
index 00000000..a06b74be
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/common/transport_private.h
@@ -0,0 +1,38 @@
+/*
+ * 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 transport_private.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef Libccnx_transport_private_h
+#define Libccnx_transport_private_h
+
+#include <ccnx/transport/common/transport_MetaMessage.h>
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+struct transport_operations {
+ void* (*Create)(void);
+ int (*Open)(void *ctx, CCNxTransportConfig *transportConfig);
+ int (*Send)(void *ctx, int desc, CCNxMetaMessage *msg, const struct timeval *timeout);
+ TransportIOStatus (*Recv)(void *ctx, int desc, CCNxMetaMessage **msg, const struct timeval *timeout);
+ int (*Close)(void *ctx, int desc);
+ int (*Destroy)(void **ctx);
+ int (*PassCommand)(void *ctx, void *command);
+};
+#endif // Libccnx_transport_private_h
diff --git a/libccnx-transport-rta/ccnx/transport/librta_About.c b/libccnx-transport-rta/ccnx/transport/librta_About.c
new file mode 100644
index 00000000..ed14330c
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/librta_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T09:29:05Z
+
+#include "librta_About.h"
+
+const char *librta_What = "@(#)" "librta " RELEASE_VERSION " 2017-02-20T14:19:07.130301"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+librtaAbout_Name(void)
+{
+ return "librta";
+}
+
+const char *
+librtaAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+librtaAbout_About(void)
+{
+ return "librta "RELEASE_VERSION " 2017-02-20T14:19:07.130301" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+librtaAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+librtaAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+librtaAbout_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-transport-rta/ccnx/transport/librta_About.h b/libccnx-transport-rta/ccnx/transport/librta_About.h
new file mode 100644
index 00000000..91092b13
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/librta_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170215.54ef86fe 2017-02-15T09:29:05Z
+
+#ifndef librta_About_h
+#define librta_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *librta_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *librtaAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *librtaAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *librtaAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *librtaAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *librtaAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *librtaAbout_LongNotice(void);
+
+#endif // librta_About_h
diff --git a/libccnx-transport-rta/ccnx/transport/test_tools/bent_pipe.c b/libccnx-transport-rta/ccnx/transport/test_tools/bent_pipe.c
new file mode 100644
index 00000000..bf2c68db
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/test_tools/bent_pipe.c
@@ -0,0 +1,850 @@
+/*
+ * 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 <LongBow/debugging.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <math.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_EventTimer.h>
+#include <parc/algol/parc_EventQueue.h>
+#include <parc/algol/parc_EventBuffer.h>
+#include <parc/algol/parc_EventSocket.h>
+#include "bent_pipe.h"
+
+#define MAX_CONN 10
+
+struct packet_wrapper {
+ struct timeval deadline;
+ int ingress_fd;
+ uint8_t *pbuff;
+ size_t pbuff_len;
+
+ TAILQ_ENTRY(packet_wrapper) list;
+};
+
+struct bentpipe_conn {
+ int client_fd;
+ PARCEventQueue *bev;
+ BentPipeState *parent;
+
+ // after reading a header, this is how long the next message is
+ size_t msg_length;
+
+ // queue to send stuff up the connection
+ unsigned bytes_in_queue;
+ unsigned count_in_queue;
+ struct timeval last_deadline;
+ TAILQ_HEAD(, packet_wrapper) output_queue;
+
+ PARCEventTimer *timer_event;
+};
+
+struct bentpipe_state {
+ char *local_name;
+ PARCEventScheduler *base;
+ PARCEventSocket *listenerUnix;
+
+ struct bentpipe_conn conns[MAX_CONN];
+ unsigned conn_count;
+
+ pthread_t router_thread;
+
+ bool use_params;
+ double loss_rate;
+ unsigned buffer_bytes;
+ double mean_sec_delay;
+ double bytes_per_sec;
+
+ pthread_mutex_t startup_mutex;
+ pthread_cond_t startup_cond;
+ unsigned magic;
+ bool startup_running;
+
+ // used to signal into the thread to stop
+ bool killme;
+ PARCEventTimer *keep_alive_event;
+
+ // these track the state of sigpipe before we
+ // go into a write, so we can re-set the state
+
+ // sigpipe_pending indicates that it was pending before our call
+ bool sigpipe_pending;
+
+ // sigpipe_blocked means that it was blocked before our call, so
+ // don't unblock it when we're done
+ bool sigpipe_blocked;
+
+ // debugging output
+ bool chattyOutput;
+};
+
+typedef struct {
+ uint32_t pid;
+ uint32_t fd;
+ uint32_t length;
+ uint32_t pad; // pad out to 16 bytes
+} __attribute__ ((packed)) localhdr;
+
+static int setup_local(BentPipeState*bp);
+static void
+listener_cb(int fd, struct sockaddr *sa, int socklen, void *user_data);
+
+static void *run_bentpipe(void *arg);
+
+static void conn_readcb(PARCEventQueue *bev, PARCEventType event, void *connection);
+static void reflect(struct bentpipe_conn *conn, uint8_t *pbuff, size_t pbuff_len);
+
+static void
+queue_with_delay(struct bentpipe_conn *conn, uint8_t *pbuff, size_t pbuff_len, int i);
+
+static void timer_cb(int fd, PARCEventType what, void *user_data);
+static void set_timer(struct bentpipe_conn *conn, struct timeval delay);
+static void keepalive_cb(int fd, PARCEventType what, void *user_data);
+void conn_errorcb(PARCEventQueue *bev, PARCEventQueueEventType events, void *user_framework);
+
+#define MAGIC 0x01020304
+
+// ===============
+
+static void
+lock_bentpipe(BentPipeState *bp)
+{
+ int res = pthread_mutex_lock(&bp->startup_mutex);
+ assertTrue(res == 0, "error from pthread_mutex_lock: %d", res);
+}
+
+static void
+unlock_bentpipe(BentPipeState *bp)
+{
+ int res = pthread_mutex_unlock(&bp->startup_mutex);
+ assertTrue(res == 0, "error from pthread_mutex_unlock: %d", res);
+}
+
+static void
+wait_bentpipe(BentPipeState *bp)
+{
+ int res = pthread_cond_wait(&bp->startup_cond, &bp->startup_mutex);
+ assertTrue(res == 0, "error from pthread_mutex_unlock: %d", res);
+}
+
+static void
+signal_bentpipe(BentPipeState *bp)
+{
+ int res = pthread_cond_signal(&bp->startup_cond);
+ assertTrue(res == 0, "error from pthread_mutex_unlock: %d", res);
+}
+
+/**
+ * if SIGPIPE was pending before we are called, don't do anything.
+ * Otherwise, mask SIGPIPE
+ */
+static void
+capture_sigpipe(BentPipeState *bp)
+{
+#if !defined(SO_NOSIGPIPE)
+ sigset_t pending;
+ sigemptyset(&pending);
+ sigpending(&pending);
+ bp->sigpipe_pending = sigismember(&pending, SIGPIPE);
+ if (!bp->sigpipe_pending) {
+ sigset_t sigpipe_mask;
+ sigemptyset(&sigpipe_mask);
+ sigaddset(&sigpipe_mask, SIGPIPE);
+
+ sigset_t blocked;
+ sigemptyset(&blocked);
+ pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &blocked);
+ bp->sigpipe_blocked = sigismember(&blocked, SIGPIPE);
+ }
+#endif
+}
+
+static void
+release_sigpipe(BentPipeState *bp)
+{
+#if !defined(SO_NOSIGPIPE)
+ // If sigpipe was previously pending, we didnt block it, so
+ // nothing new to do
+ if (!bp->sigpipe_pending) {
+ sigset_t pending;
+
+ sigset_t sigpipe_mask;
+ sigemptyset(&sigpipe_mask);
+ sigaddset(&sigpipe_mask, SIGPIPE);
+
+ sigemptyset(&pending);
+ sigpending(&pending);
+
+ if (!bp->sigpipe_blocked) {
+ pthread_sigmask(SIG_UNBLOCK, &sigpipe_mask, NULL);
+ }
+ }
+#endif
+}
+
+BentPipeState *
+bentpipe_Create(const char *local_name)
+{
+ assertNotNull(local_name, "Parameter local_name must be non-null");
+
+ struct timeval keepalive_timeout = { .tv_sec = 0, .tv_usec = 500000 };
+
+ BentPipeState *bp = parcMemory_AllocateAndClear(sizeof(struct bentpipe_state));
+ assertNotNull(bp, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(struct bentpipe_state));
+
+ bp->local_name = parcMemory_StringDuplicate((char *) local_name, 1024);
+ bp->conn_count = 0;
+ bp->base = parcEventScheduler_Create();
+ bp->use_params = false;
+ bp->chattyOutput = false;
+
+ if (!bp->base) {
+ fprintf(stderr, "Could not initialize PARCEventScheduler!\n");
+ return NULL;
+ }
+
+ pthread_mutex_init(&bp->startup_mutex, NULL);
+ pthread_cond_init(&bp->startup_cond, NULL);
+ bp->startup_running = false;
+ bp->magic = MAGIC;
+ bp->keep_alive_event = parcEventTimer_Create(bp->base, PARCEventType_Persist, keepalive_cb, bp);
+ parcEventTimer_Start(bp->keep_alive_event, &keepalive_timeout);
+
+ for (int i = 0; i < MAX_CONN; i++) {
+ bp->conns[i].bytes_in_queue = 0;
+ TAILQ_INIT(&bp->conns[i].output_queue);
+ bp->conns[i].timer_event = parcEventTimer_Create(bp->base, 0, timer_cb, &bp->conns[i]);
+ }
+ setup_local(bp);
+ capture_sigpipe(bp);
+ return bp;
+}
+
+void
+bentpipe_Destroy(BentPipeState **bpPtr)
+{
+ BentPipeState *bp;
+ assertNotNull(bpPtr, "%s got null double pointer\n", __func__);
+ bp = *bpPtr;
+ assertNotNull(bp, "%s got null dereference\n", __func__);
+
+ assertFalse(bp->startup_running, "calling destroy on a running bentpipe\n");
+
+ int i;
+ for (i = 0; i < MAX_CONN; i++) {
+ if (bp->conns[i].client_fd > 0) {
+ // this closes it too
+ parcEventQueue_Destroy(&(bp->conns[i].bev));
+ bp->conns[i].client_fd = 0;
+ }
+ parcEventTimer_Destroy(&(bp->conns[i].timer_event));
+ }
+
+ parcEventTimer_Destroy(&(bp->keep_alive_event));
+ parcEventSocket_Destroy(&(bp->listenerUnix));
+ parcEventScheduler_Destroy(&(bp->base));
+ bp->conn_count = 0;
+
+ int failure = unlink(bp->local_name);
+ if (failure) {
+ printf("Error unlinking '%s': (%d) %s\n", bp->local_name, errno, strerror(errno));
+ }
+
+ release_sigpipe(bp);
+ parcMemory_Deallocate((void **) &(bp->local_name));
+ parcMemory_Deallocate((void **) &bp);
+}
+
+void
+bentpipe_SetChattyOutput(BentPipeState *bp, bool chattyOutput)
+{
+ bp->chattyOutput = chattyOutput;
+}
+
+int
+bentpipe_Start(BentPipeState *bp)
+{
+ assertFalse(bp->startup_running, "bentpipe_Start already running");
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+
+ assertTrue(pthread_create(&bp->router_thread, &attr, run_bentpipe, bp) == 0, "pthread_create failed.");
+// if (pthread_create(&bp->router_thread, &attr, run_bentpipe, bp) != 0) {
+// perror("pthread_create router thread");
+// abort();
+// }
+
+ lock_bentpipe(bp);
+ while (!bp->startup_running) {
+ wait_bentpipe(bp);
+ }
+ unlock_bentpipe(bp);
+
+ return 0;
+}
+
+int
+bentpipe_Stop(BentPipeState *bp)
+{
+ assertTrue(bp->magic == MAGIC, "Magic is not magic value! got %08X", bp->magic);
+ assertTrue(bp->startup_running, "Calling stop on a stopped bentpipe\n");
+
+ bp->killme = true;
+
+ // wait until exist
+ lock_bentpipe(bp);
+ while (bp->startup_running) {
+ wait_bentpipe(bp);
+ }
+ unlock_bentpipe(bp);
+
+ return 0;
+}
+
+// ==================================
+
+void
+listener_errorcb(PARCEventScheduler *base, int error, char *errorString, void *addr_unix)
+{
+ fprintf(stderr, "Got an error %d (%s) on the listener. "
+ "Shutting down.\n", error, errorString);
+
+ parcEventScheduler_Stop(base, NULL);
+}
+
+static int
+setup_local(BentPipeState*bp)
+{
+ // cleanup anything left on file system
+ unlink(bp->local_name);
+
+ struct sockaddr_un addr_unix;
+ memset(&addr_unix, 0, sizeof(addr_unix));
+
+ addr_unix.sun_family = PF_UNIX;
+ strcpy(addr_unix.sun_path, bp->local_name);
+
+ if (bp->chattyOutput) {
+ printf("bent_pipe Creating '%s'", bp->local_name);
+ }
+
+ bp->listenerUnix = parcEventSocket_Create(bp->base,
+ listener_cb,
+ listener_errorcb,
+ (void *) bp,
+ (struct sockaddr*) &addr_unix,
+ sizeof(addr_unix));
+
+ assertNotNull(bp->listenerUnix, "parcEventSocket_Create failed: unix %s", bp->local_name);
+
+ return 0;
+}
+
+static void *
+run_bentpipe(void *arg)
+{
+ BentPipeState *bp = (BentPipeState *) arg;
+
+ if (bp->chattyOutput) {
+ printf("%s starting\n", __func__);
+ }
+
+ // The keepalive timer will signal that we have started running
+ parcEventScheduler_Start(bp->base, PARCEventSchedulerDispatchType_Blocking);
+
+ if (bp->chattyOutput) {
+ printf("%s exiting\n", __func__);
+ }
+
+ lock_bentpipe(bp);
+ bp->startup_running = false;
+ signal_bentpipe(bp);
+ unlock_bentpipe(bp);
+
+ pthread_exit(NULL);
+}
+
+static struct bentpipe_conn *
+allocate_connection(BentPipeState *bp)
+{
+ if (bp->conn_count == MAX_CONN) {
+ printf("allocate_connection: connection count is %d, maximum count is %d\n",
+ bp->conn_count, MAX_CONN);
+ return NULL;
+ }
+
+ for (int i = 0; i < MAX_CONN; i++) {
+ if (bp->conns[i].client_fd == 0) {
+ bp->conn_count++;
+ return &bp->conns[i];
+ }
+ }
+
+ // should never get here
+ abort();
+}
+
+static void
+deallocate_connection(BentPipeState *bp, struct bentpipe_conn *conn)
+{
+ assertTrue(bp->conn_count > 0, "invalid state, called deallocate_connection when conn_count is zero");
+
+ conn->client_fd = 0;
+
+ if (bp->chattyOutput) {
+ printf("destroying connection %p eventqueue %p\n", (void *) conn, (void *) conn->bev);
+ }
+
+ parcEventQueue_Disable(conn->bev, PARCEventType_Read);
+ parcEventQueue_Destroy(&(conn->bev));
+
+ // this unschedules any callbacks, but the timer is still allocated
+ // timer_event is freed in bentPipe_Destroy()
+ parcEventTimer_Stop(conn->timer_event);
+
+ bp->conn_count--;
+}
+
+/*
+ * Server accepts a new client
+ */
+static void
+listener_cb(int fd, struct sockaddr *sa, int socklen, void *user_data)
+{
+ BentPipeState *bp = (BentPipeState *) user_data;
+
+ // allocate a connection
+ struct bentpipe_conn *conn = allocate_connection(bp);
+
+ conn->parent = bp;
+ conn->client_fd = fd;
+
+ // Set non-blocking flag
+ int flags = fcntl(fd, F_GETFL, NULL);
+ assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno);
+ int failure = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+ assertFalse(failure, "fcntl failed to set file descriptor flags (%d)\n", errno);
+
+#if defined(SO_NOSIGPIPE)
+ int set = 1;
+ setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *) &set, sizeof(int));
+#endif
+
+ conn->bev = parcEventQueue_Create(bp->base, fd, PARCEventQueueOption_CloseOnFree | PARCEventQueueOption_DeferCallbacks);
+ if (!conn->bev) {
+ fprintf(stderr, "Error constructing parcEventQueue!");
+ parcEventScheduler_Abort(bp->base);
+ return;
+ }
+
+ parcEventQueue_SetCallbacks(conn->bev, conn_readcb, NULL, conn_errorcb, (void *) conn);
+ parcEventQueue_Enable(conn->bev, PARCEventType_Read);
+
+ if (bp->chattyOutput) {
+ printf("%s accepted connection on fd %d conn %p eventqueue %p\n",
+ __func__, fd, (void *) conn, (void *) conn->bev);
+ }
+}
+
+/*
+ * Return 1 if we read an entire message and we can try another one.
+ * return 0 if we're waiting for bytes.
+ */
+static int
+single_read(PARCEventQueue *bev, struct bentpipe_conn *conn)
+{
+ BentPipeState *bp = conn->parent;
+ PARCEventBuffer *input = parcEventBuffer_GetQueueBufferInput(bev);
+ size_t read_length = parcEventBuffer_GetLength(input);
+ int ret = 0;
+
+ if (bp->chattyOutput) {
+ printf("single_read: connid %d read %zu bytes\n", conn->client_fd, read_length);
+ }
+
+ if (read_length == 0) {
+ // 0 length means EOF, close the connection
+ if (bp->chattyOutput) {
+ printf("single_read: connid %d read_length %zu, EOF, closing connection\n",
+ conn->client_fd,
+ read_length);
+ }
+ deallocate_connection(conn->parent, conn);
+ parcEventBuffer_Destroy(&input);
+ return 0;
+ }
+
+ // head we read the message header, which sets the message length?
+ if (conn->msg_length == 0) {
+ // did we read a whole header?
+ if (read_length >= sizeof(localhdr)) {
+ // yes we did, we can now read the message header then try to read the whole message
+ // Note that this does not remove the header from the buffer
+
+ localhdr *msg_hdr = (localhdr *) parcEventBuffer_Pullup(input, sizeof(localhdr));
+ conn->msg_length = msg_hdr->length;
+
+ assertTrue(conn->msg_length > 0, "single_read: msg_hdr length is 0!");
+ assertTrue(conn->msg_length < 64000, "single_read: msg_hdr length too large: %zu", conn->msg_length);
+
+ if (bp->chattyOutput) {
+ printf("single_read: %s start read_length %zu msg_length %zu\n", __func__, read_length, conn->msg_length);
+ }
+ } else {
+ // no we did not, wait for more data before procesing.
+
+ if (bp->chattyOutput) {
+ printf("single_read: %s short read %zu\n", __func__, read_length);
+ }
+ }
+ }
+
+ // if read_length < sizeof(localhdr), then this is false.
+ // Otherwise, we've read the header and set msg_length, so if read_length
+ // is greater than the sum we have a full message plus header
+
+ if (read_length >= sizeof(localhdr) + conn->msg_length) {
+ size_t pbuff_len = sizeof(localhdr) + conn->msg_length;
+ int bytes_removed;
+
+ uint8_t *pbuff = parcMemory_Allocate(pbuff_len);
+ assertNotNull(pbuff, "parcMemory_Allocate(%zu) returned NULL", pbuff_len);
+
+ // dequeue into packet buffer
+ bytes_removed = parcEventBuffer_Read(input, (void *) pbuff, pbuff_len);
+ assertTrue(bytes_removed == pbuff_len, "parcEventBuffer read wrong length, expected %zu got %d", pbuff_len, bytes_removed);
+
+ // now reset message length for next packet
+ conn->msg_length = 0;
+
+ if (bp->chattyOutput) {
+ printf("connid %d msg_length %zu read_length %zu, resetting low water mark\n",
+ conn->client_fd,
+ pbuff_len,
+ read_length);
+
+ longBowDebug_MemoryDump((char *) pbuff, pbuff_len);
+ }
+
+ // reflect will free the memory
+ reflect(conn, pbuff, pbuff_len);
+
+ // we could do more after this
+ if (read_length > pbuff_len) {
+ ret = 1;
+ }
+ } else {
+ // we do not have an entire message, so skip and wait for more to be read
+ }
+ parcEventBuffer_Destroy(&input);
+ return ret;
+}
+
+static void
+conn_readcb(PARCEventQueue *bev, PARCEventType event, void *user_data)
+{
+ struct bentpipe_conn *conn = (struct bentpipe_conn *) user_data;
+
+ // drain the input buffer
+ while (single_read(bev, conn)) {
+ // empty
+ }
+}
+
+/*
+ * reflect a message to other connections
+ *
+ * We should use the zero-copy deferred write...
+ */
+static void
+reflect(struct bentpipe_conn *conn, uint8_t *pbuff, size_t pbuff_len)
+{
+ int i;
+ BentPipeState *bp = conn->parent;
+
+ for (i = 0; i < MAX_CONN; i++) {
+ if (bp->conns[i].client_fd > 0 && bp->conns[i].client_fd != conn->client_fd) {
+ int res;
+
+ if (bp->chattyOutput) {
+ printf("%s connid %d adding buffer length %zu\n", __func__, conn[i].client_fd, pbuff_len);
+ }
+
+ if (bp->use_params) {
+ uint8_t *copy = parcMemory_Allocate(pbuff_len);
+ assertNotNull(copy, "parcMemory_Allocate(%zu) returned NULL", pbuff_len);
+ memcpy(copy, pbuff, pbuff_len);
+ queue_with_delay(conn, copy, pbuff_len, i);
+ } else {
+ res = parcEventQueue_Write(bp->conns[i].bev, pbuff, pbuff_len);
+ assertTrue(res == 0, "%s got parcEventQueue_Write error\n", __func__);
+
+ localhdr *msg_hdr = (localhdr *) pbuff;
+ assertTrue(msg_hdr->length + sizeof(localhdr) == pbuff_len,
+ "msg_hdr messed up! expected %zu got %zu",
+ msg_hdr->length + sizeof(localhdr),
+ pbuff_len);
+ }
+ }
+ }
+
+ parcMemory_Deallocate((void **) &pbuff);
+}
+
+/**
+ * Queue a packet for later delivery. We calculate the needed delay and insert it
+ * in the connection's output_queue. If there is not a timer running (i.e. there are now
+ * exactly 1 elements in the queue), we start the timer for the connection.
+ *
+ * If the output queue is full, the packet might be freed and not added to the output queue.
+ */
+static void
+queue_with_delay(struct bentpipe_conn *conn, uint8_t *pbuff, size_t pbuff_len, int i)
+{
+ BentPipeState *bp = conn->parent;
+ double delay_sec;
+
+ struct timeval now;
+ struct timeval delay_tv;
+ struct timeval deadline;
+
+ gettimeofday(&now, NULL);
+
+ // 1) Apply loss rate
+ if (drand48() < bp->loss_rate) {
+ if (bp->chattyOutput) {
+ printf("%s random drop\n", __func__);
+ }
+ parcMemory_Deallocate((void **) &pbuff);
+ return;
+ }
+
+ // 2) will it fit?
+ if (pbuff_len + bp->conns[i].bytes_in_queue >= bp->buffer_bytes) {
+ if (bp->chattyOutput) {
+ printf("%s queue full\n", __func__);
+ }
+ parcMemory_Deallocate((void **) &pbuff);
+ return;
+ }
+
+ // 3) Determine delay
+ delay_sec = (double) pbuff_len / bp->bytes_per_sec;
+
+ // 4) exponential delay
+ delay_sec += -1 * log(drand48()) * bp->mean_sec_delay;
+
+ delay_tv.tv_sec = (time_t) floor(delay_sec);
+ delay_tv.tv_usec = (suseconds_t) floor((delay_sec - floor(delay_sec)) * 1E+6);
+
+ struct packet_wrapper *wrapper = parcMemory_Allocate(sizeof(struct packet_wrapper));
+ assertNotNull(wrapper, "parcMemory_Allocate(%zu) returned NULL", sizeof(struct packet_wrapper));
+ wrapper->ingress_fd = conn->client_fd;
+ wrapper->pbuff = pbuff;
+ wrapper->pbuff_len = pbuff_len;
+
+ timeradd(&now, &delay_tv, &deadline);
+
+ wrapper->deadline = deadline;
+ bp->conns[i].last_deadline = deadline;
+ bp->conns[i].bytes_in_queue += pbuff_len;
+
+ bp->conns[i].count_in_queue++;
+ TAILQ_INSERT_TAIL(&bp->conns[i].output_queue, wrapper, list);
+
+ if (bp->chattyOutput) {
+ printf("%s queue %d fd %d count %d\n", __func__, i, bp->conns[i].client_fd, bp->conns[i].count_in_queue);
+ }
+
+ // if this is first item in queue, set a timer
+ if (bp->conns[i].count_in_queue == 1) {
+ set_timer(&bp->conns[i], delay_tv);
+ }
+}
+
+int
+bentpipe_Params(BentPipeState *bp, double loss_rate, unsigned buffer_bytes, double mean_sec_delay, double bytes_per_sec)
+{
+ bp->use_params = true;
+ bp->loss_rate = loss_rate;
+ bp->buffer_bytes = buffer_bytes;
+ bp->mean_sec_delay = mean_sec_delay;
+ bp->bytes_per_sec = bytes_per_sec;
+ return 0;
+}
+
+static
+void
+keepalive_cb(int fd, PARCEventType what, void *user_data)
+{
+ struct bentpipe_state *bp = (struct bentpipe_state *) user_data;
+
+ if (!bp->startup_running) {
+ // indicate to anyone waiting that we're really running
+ if (bp->chattyOutput) {
+ printf("%s signalling startup_running\n", __func__);
+ }
+
+ lock_bentpipe(bp);
+ bp->startup_running = true;
+ signal_bentpipe(bp);
+ unlock_bentpipe(bp);
+ return;
+ }
+
+ if (bp->killme) {
+ parcEventScheduler_Abort(bp->base);
+ return;
+ }
+}
+
+/**
+ * Each connection has its own timer. The timer is used to defer sending packets to a later time,
+ * such as to realize traffic shaping.
+ */
+static void
+timer_cb(int fd, PARCEventType what, void *user_data)
+{
+ struct bentpipe_conn *conn = (struct bentpipe_conn *) user_data;
+ BentPipeState *bp = conn->parent;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+ while (!TAILQ_EMPTY(&conn->output_queue)) {
+ int res;
+ struct packet_wrapper *wrapper = TAILQ_FIRST(&conn->output_queue);
+
+ assertTrue(conn->count_in_queue > 0, "invalid state: count_in_queue is 0");
+
+ if (timercmp(&now, &wrapper->deadline, <)) {
+ break;
+ }
+
+ conn->bytes_in_queue -= wrapper->pbuff_len;
+ conn->count_in_queue--;
+
+ res = parcEventQueue_Write(conn->bev, wrapper->pbuff, wrapper->pbuff_len);
+ assertTrue(res == 0, "got parcEventQueue_Write error\n");
+
+ if (bp->chattyOutput) {
+ printf("%3.9f output conn %d bytes %zu\n",
+ now.tv_sec + now.tv_usec * 1E-6, conn->client_fd, wrapper->pbuff_len);
+ }
+
+ TAILQ_REMOVE(&conn->output_queue, wrapper, list);
+
+ parcMemory_Deallocate((void **) &(wrapper->pbuff));
+ parcMemory_Deallocate((void **) &wrapper);
+ }
+
+ if (!TAILQ_EMPTY(&conn->output_queue)) {
+ struct packet_wrapper *wrapper = TAILQ_FIRST(&conn->output_queue);
+ struct timeval delay;
+ timersub(&wrapper->deadline, &now, &delay);
+
+ if (bp->chattyOutput) {
+ printf("connid %d scheduling next timer delay %.6f\n",
+ conn->client_fd, delay.tv_sec + 1E-6 * delay.tv_usec);
+ }
+
+ assertTrue(delay.tv_sec >= 0 && delay.tv_usec >= 0,
+ "Got negative delay: now %.6f deadline %.6f delay %.6f",
+ now.tv_sec + 1E-6 * now.tv_usec,
+ wrapper->deadline.tv_sec + 1E-6 * wrapper->deadline.tv_usec,
+ delay.tv_sec + 1E-6 * delay.tv_usec);
+
+ if (delay.tv_sec == 0 && delay.tv_usec < 1000) {
+ delay.tv_usec = 1000;
+ }
+
+ set_timer(conn, delay);
+ }
+}
+
+static void
+set_timer(struct bentpipe_conn *conn, struct timeval delay)
+{
+ BentPipeState *bp = conn->parent;
+ // this replaces any prior events
+
+ if (delay.tv_usec < 1000) {
+ delay.tv_usec = 1000;
+ }
+
+ if (delay.tv_sec < 0) {
+ delay.tv_sec = 0;
+ }
+
+ if (bp->chattyOutput) {
+ printf("%s connid %d delay %.6f timer_event %p\n",
+ __func__,
+ conn->client_fd,
+ delay.tv_sec + 1E-6 * delay.tv_usec,
+ (void *) conn->timer_event);
+ }
+
+ parcEventTimer_Start(conn->timer_event, &delay);
+}
+
+void
+conn_errorcb(PARCEventQueue *bev, PARCEventQueueEventType events, void *user_data)
+{
+ if (events & PARCEventQueueEventType_EOF) {
+ struct bentpipe_conn *conn = (struct bentpipe_conn *) user_data;
+
+ if (conn->parent->chattyOutput) {
+ printf("%s Got EOF on connid %d fd %d socket\n",
+ __func__,
+ conn->client_fd,
+ parcEventQueue_GetFileDescriptor(bev));
+ }
+
+ deallocate_connection(conn->parent, conn);
+ }
+
+ if (events & PARCEventQueueEventType_Error) {
+ struct bentpipe_conn *conn = (struct bentpipe_conn *) user_data;
+
+ printf("%s Got error on connid %d fd %d socket: %s\n",
+ __func__,
+ conn->client_fd,
+ parcEventQueue_GetFileDescriptor(bev),
+ strerror(errno));
+
+ deallocate_connection(conn->parent, conn);
+ }
+}
diff --git a/libccnx-transport-rta/ccnx/transport/test_tools/bent_pipe.h b/libccnx-transport-rta/ccnx/transport/test_tools/bent_pipe.h
new file mode 100644
index 00000000..8c726b8b
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/test_tools/bent_pipe.h
@@ -0,0 +1,148 @@
+/*
+ * 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 bent_pipe.h
+ * @brief <#Brief Description#>
+ *
+ * PF_UNIX "forwarder" for testing. It's a bent pipe. Whatever comes down
+ * one connection goes up all the others.
+ *
+ * It runs in its own thread and uses an event model.
+ *
+ * We capture SIG_PIPE when doing a write so this test code does not
+ * trigger a process-wide SIG_PIPE. Unless we have SO_SIGPIPE, then we'll use that.
+ *
+ */
+#ifndef Libccnx_bent_pipe_h
+#define Libccnx_bent_pipe_h
+
+#include <stdbool.h>
+
+struct bentpipe_state;
+/**
+ *
+ * @see bentpipe_Create
+ */
+typedef struct bentpipe_state BentPipeState;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+BentPipeState *bentpipe_Create(const char *local_name);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void bentpipe_Destroy(BentPipeState **statePtr);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+int bentpipe_Start(BentPipeState *bp);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+int bentpipe_Stop(BentPipeState *bp);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void bentpipe_SetChattyOutput(BentPipeState *bp, bool chattyOutput);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+int bentpipe_Params(BentPipeState *bp, double loss_rate, unsigned buffer_bytes, double mean_sec_delay, double bytes_per_sec);
+#endif // Libccnx_bent_pipe_h
diff --git a/libccnx-transport-rta/ccnx/transport/test_tools/ethersend.c b/libccnx-transport-rta/ccnx/transport/test_tools/ethersend.c
new file mode 100644
index 00000000..9db1a7e3
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/test_tools/ethersend.c
@@ -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.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <ifaddrs.h>
+#include <assert.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+typedef uint8_t u_char;
+typedef uint16_t u_short;
+typedef uint32_t u_int;
+
+
+#include <pcap.h>
+
+#define ETHERTYPE 0x0801
+
+struct _packet {
+ u_int8_t dst[6];
+ u_int8_t src[6];
+ u_int16_t ethertype;
+ u_int8_t data[0];
+} __attribute__((packed));
+
+
+static void send_file(pcap_t *handle, uint8_t smac[], uint8_t dmac[], const char *filename);
+
+
+static
+void
+printhex(u_int8_t *buffer, int length)
+{
+ int i;
+ for (i = 0; i < length; i++) {
+ printf("%02X", buffer[i]);
+ }
+}
+
+
+
+static void
+send_file(pcap_t *handle, uint8_t smac[], uint8_t dmac[], const char *filename)
+{
+ struct stat statbuf;
+
+ struct _packet *packet = malloc(1500);
+ memset(packet, 0, 1500);
+
+ int fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ perror("Error opening file: ");
+ abort();
+ }
+
+ if (fstat(fd, &statbuf) < 0) {
+ perror("fstat error");
+ abort();
+ }
+
+ uint8_t *src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (src == MAP_FAILED) {
+ perror("mmap error");
+ abort();
+ }
+
+ assert(statbuf.st_size <= 1500);
+
+ size_t len = sizeof(struct _packet) + statbuf.st_size;
+ printf("Sending config/query size %zu\n", len);
+
+ memcpy(packet->dst, dmac, 6);
+ memcpy(packet->src, smac, 6);
+
+ packet->ethertype = htons(ETHERTYPE);
+
+ memcpy(packet->data, src, statbuf.st_size);
+
+ int x = pcap_inject(handle, packet, len);
+ printf("%s wrote %d bytes\n", __func__, x);
+
+ free(packet);
+}
+
+static
+void
+get_mac_address(const char *deviceName, u_int8_t *mac)
+{
+ struct ifaddrs *ifap;
+ struct ifaddrs *next;
+
+ int x = getifaddrs(&ifap);
+ if (x != 0) {
+ perror("getifaddrs");
+ exit(EXIT_FAILURE);
+ }
+
+ next = ifap;
+ while (next != NULL) {
+#if defined(__APPLE__)
+ if (strstr(deviceName, next->ifa_name) != NULL && next->ifa_addr->sa_family == AF_LINK)
+#elif defined(__linux__)
+ if (strstr(deviceName, next->ifa_name) != NULL && next->ifa_addr->sa_family == AF_PACKET)
+#else
+#error Unsupported platform
+#endif
+ {
+ memcpy(mac, next->ifa_addr->sa_data + 9, 6);
+ break;
+ }
+ next = next->ifa_next;
+ }
+ freeifaddrs(ifap);
+}
+
+static void
+macStringToArray(const char *string, size_t outputLength, uint8_t output[])
+{
+ assert(outputLength == 6);
+
+ sscanf(string, "%02x:%02x:%02x:%02x:%02x:%02x", &output[0], &output[1], &output[2], &output[3], &output[4], &output[5]);
+}
+
+int
+main(int argc, const char *argv[])
+{
+ if (argc != 4 || argv[1][0] == '-') {
+ printf("usage: ethersend dev dst filename\n");
+ printf("\n");
+ printf("Will send filename as the payload of an ethernet frame to dst\n");
+ printf("\n");
+ printf("example: ethersend eth0 a8:20:66:3b:30:bc interest.bin\n");
+ printf("\n");
+ exit(EXIT_FAILURE);
+ }
+
+ pcap_t *handle; /* Session handle */
+ const char *dev = argv[1]; /* The device to sniff on */
+ char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */
+ struct bpf_program fp; /* The compiled filter */
+ char filter_exp[1024]; /* The filter expression */
+ bpf_u_int32 mask; /* Our netmask */
+ bpf_u_int32 net; /* Our IP */
+
+ sprintf(filter_exp, "ether proto 0x%04X", ETHERTYPE);
+
+ printf("dev = %s\n", dev);
+
+ /* Find the properties for the device */
+ if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
+ fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
+ net = 0;
+ mask = 0;
+ }
+
+ u_int8_t mymac[6];
+ get_mac_address(dev, mymac);
+ printf("My mac address: "); printhex(mymac, 6); printf("\n");
+
+ u_int8_t dmac[6];
+ macStringToArray(argv[2], 6, dmac);
+ printf("dmac address : "); printhex(dmac, 6); printf("\n");
+
+
+ /* Open the session in promiscuous mode */
+ handle = pcap_open_live(dev, 1500, 1, 1000, errbuf);
+ if (handle == NULL) {
+ fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
+ return (2);
+ }
+
+ /* Compile and apply the filter */
+ if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
+ fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
+ return (2);
+ }
+
+ if (pcap_setfilter(handle, &fp) == -1) {
+ fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
+ return (2);
+ }
+
+ send_file(handle, mymac, dmac, argv[3]);
+
+
+ pcap_close(handle);
+ return (0);
+}
+
diff --git a/libccnx-transport-rta/ccnx/transport/test_tools/pktgen.c b/libccnx-transport-rta/ccnx/transport/test_tools/pktgen.c
new file mode 100644
index 00000000..8f1cc087
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/test_tools/pktgen.c
@@ -0,0 +1,195 @@
+/*
+ * 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.
+ */
+
+/**
+ * Generate packets
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+typedef enum {
+ MODE_SEND,
+ MODE_REPLY
+} PktGenMode;
+
+typedef enum {
+ ENCAP_ETHER,
+ ENCAP_UDP
+} PktGenEncap;
+
+typedef enum {
+ PKTGEN_STREAM,
+ PKTGEN_STOPWAIT
+} PktGenFlow;
+
+typedef struct {
+ PktGenMode mode;
+ PktGenEncap encap;
+ PktGenFlow flow;
+
+ char *ifname;
+ char *etherOrIp;
+ char *etherType;
+ unsigned count;
+
+ struct timeval startTime;
+ struct timeval stopTime;
+ unsigned packetCount;
+} PktGen;
+
+// ======================================================================
+
+static void
+usage(void)
+{
+ printf("usage: \n");
+ printf(" This program functions as a requester and a responder. They operate in a pair.\n");
+ printf(" The test can run over raw Ethernet encapsulation or over UDP\n");
+ printf(" The <count> parameter can be an integer or use a 'kmg' suffix for 1000, 1E+6, or 1E+9\n");
+ printf("\n");
+ printf(" pktgen send ether <ifname> <dstmac> [ethertype] count <n> (stream | stopwait)\n");
+ printf(" pktgen reply ether <ifname> [count <n>]\n");
+ printf("\n");
+ printf(" This mode sends either a stream or stop-and-wait request to an Ethernet peer\n");
+ printf(" pktgen send udp <ifname> <dstip> <dstport> count <n> (stream | stopwait)\n");
+ printf(" pktgen reply udp <ifname> [count <n>]\n");
+ printf("\n");
+ printf(" Examples:\n");
+ printf(" This uses the standard Ethertype of 0x0801. The replier will stay running forever.\n");
+ printf(" pktgen send ether em1 bc:30:5b:f2:2f:60 count 1M stream\n");
+ printf(" pktgen reply ether em1\n");
+ printf("\n");
+ printf(" This uses a custom ethertype. The replier will stay running forever.\n");
+ printf(" pktgen send ether em1 bc:30:5b:f2:2f:60 0x9000 count 1M stream\n");
+ printf(" pktgen reply ether em1\n");
+ printf("\n");
+ printf(" An example with UDP\n");
+ printf(" pktgen send udp em1 10.1.0.2 9695 count 1M stopwait\n");
+ printf(" pktgen reply udp em1\n");
+ printf("\n");
+}
+
+static PktGen
+parseCommandLine(int argc, char *argv[argc])
+{
+ PktGen pktgen;
+ memset(&pktgen, 0, sizeof(PktGen));
+
+ usage();
+
+ return pktgen;
+}
+
+// ======================================================================
+
+static void
+generateEther(PktGen *pktgen)
+{
+ printf("Generating %u ethernet interest messages\n", pktgen->count);
+}
+
+static void
+replyEther(PktGen *pktgen)
+{
+ printf("replying up to %u ethernet content objects messages\n", pktgen->count);
+}
+
+// ======================================================================
+
+static void
+generateUdp(PktGen *pktgen)
+{
+ printf("Generating %u UDP interest messages\n", pktgen->count);
+}
+
+static void
+replyUdp(PktGen *pktgen)
+{
+ printf("replying up to %u UDP content objects messages\n", pktgen->count);
+}
+
+
+// ======================================================================
+
+static void
+displayStatistics(PktGen *pktgen)
+{
+ printf("stats.... coming soon\n");
+}
+
+// ======================================================================
+
+static void
+runSender(PktGen *pktgen)
+{
+ switch (pktgen->encap) {
+ case ENCAP_ETHER:
+ generateEther(pktgen);
+ break;
+
+ case ENCAP_UDP:
+ generateUdp(pktgen);
+ break;
+
+ default:
+ trapIllegalValue(pktgen.encap, "Unknown encapsulation: %d", pktgen->encap);
+ }
+}
+
+static void
+runReplier(PktGen *pktgen)
+{
+ switch (pktgen->encap) {
+ case ENCAP_ETHER:
+ replyEther(pktgen);
+ break;
+
+ case ENCAP_UDP:
+ replyUdp(pktgen);
+ break;
+
+ default:
+ trapIllegalValue(pktgen.encap, "Unknown encapsulation: %d", pktgen->encap);
+ }
+}
+
+// ======================================================================
+
+int
+main(int argc, char *argv[argc])
+{
+ PktGen pktgen = parseCommandLine(argc, argv);
+
+ switch (pktgen.mode) {
+ case MODE_SEND:
+ runSender(&pktgen);
+ break;
+
+ case MODE_REPLY:
+ runReplier(&pktgen);
+ break;
+
+ default:
+ trapIllegalValue(pktgen.mode, "Unknown mode: %d", pktgen.mode);
+ }
+
+ displayStatistics(&pktgen);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/test_tools/test/.gitignore b/libccnx-transport-rta/ccnx/transport/test_tools/test/.gitignore
new file mode 100644
index 00000000..e1bb21dc
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/test_tools/test/.gitignore
@@ -0,0 +1 @@
+test_bent_pipe
diff --git a/libccnx-transport-rta/ccnx/transport/test_tools/test/test_bent_pipe.c b/libccnx-transport-rta/ccnx/transport/test_tools/test/test_bent_pipe.c
new file mode 100644
index 00000000..0fbe9683
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/test_tools/test/test_bent_pipe.c
@@ -0,0 +1,397 @@
+/*
+ * 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.
+ */
+
+//
+// test_bent_pipe.c
+// Libccnx
+//
+
+#include "../bent_pipe.c"
+
+#include <stdio.h>
+#include <sys/un.h>
+#include <strings.h>
+#include <sys/queue.h>
+#include <errno.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#define CHATTY 1
+
+static const char *local_name = "/tmp/alpha";
+
+LONGBOW_TEST_RUNNER(BentPipe)
+{
+ LONGBOW_RUN_TEST_FIXTURE(CreateDestroy);
+ LONGBOW_RUN_TEST_FIXTURE(System);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(BentPipe)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(BentPipe)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ================================
+
+LONGBOW_TEST_FIXTURE(CreateDestroy)
+{
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, create_destroy);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, create_start_stop_destroy);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateDestroy)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroy)
+{
+ if (parcMemory_Outstanding() != 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(CreateDestroy, create_destroy)
+{
+ BentPipeState *bp = bentpipe_Create(local_name);
+ bentpipe_Destroy(&bp);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, create_start_stop_destroy)
+{
+ BentPipeState *bp = bentpipe_Create(local_name);
+ bentpipe_Start(bp);
+ bentpipe_Stop(bp);
+ bentpipe_Destroy(&bp);
+}
+
+// ================================
+
+BentPipeState *system_bp;
+
+LONGBOW_TEST_FIXTURE(System)
+{
+ LONGBOW_RUN_TEST_CASE(System, two_connections);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(System)
+{
+ system_bp = bentpipe_Create(local_name);
+ bentpipe_Start(system_bp);
+
+ printf("%s created system_bp %p, running %d\n", __func__, (void *) system_bp, system_bp->startup_running);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(System)
+{
+ printf("%s stopping system_bp %p, running %d\n", __func__, (void *) system_bp, system_bp->startup_running);
+
+ bentpipe_Stop(system_bp);
+ bentpipe_Destroy(&system_bp);
+ if (parcMemory_Outstanding() != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+connect_to_bentpipe(const char *pipe_name)
+{
+ int res;
+ struct sockaddr_un addr_unix;
+ int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ perror("socket PF_LOCAL");
+ }
+
+ assertFalse(fd < 0, "socket PF_LOCAL error");
+
+ memset(&addr_unix, 0, sizeof(addr_unix));
+ addr_unix.sun_family = AF_UNIX;
+ strcpy(addr_unix.sun_path, pipe_name);
+
+ res = connect(fd, (struct sockaddr *) &addr_unix, sizeof(addr_unix));
+ if (res < 0) {
+ perror("connect");
+ }
+ assertTrue(res == 0, "error on connect");
+ return fd;
+}
+
+#define MAXSEND 1024
+#define CONN_COUNT 3
+#define MAXPENDING 128
+
+struct sendlist {
+ uint8_t buffer[MAXSEND];
+ size_t length;
+ unsigned refcount;
+};
+
+struct fdstate {
+ int fd;
+
+ struct sendlist *expected[MAXPENDING];
+ unsigned head;
+ unsigned tail;
+ unsigned count_expected;
+
+ unsigned count_send;
+ unsigned count_recv;
+
+ // these are for the next message being read
+ size_t total_read_length;
+ size_t current_read_length;
+ uint8_t pbuff[MAXSEND + 16];
+};
+
+void
+sendbuffer(int fd, struct fdstate *state)
+{
+ struct sendlist *entry = parcMemory_AllocateAndClear(sizeof(struct sendlist));
+ assertNotNull(entry, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(struct sendlist));
+ size_t len, total_len;
+ localhdr *hdr = (localhdr *) entry->buffer;
+ int i;
+ ssize_t res;
+
+ len = random() % (MAXSEND - sizeof(localhdr) - 1) + 1;
+ hdr->pid = getpid();
+ hdr->fd = fd;
+ hdr->length = (int) len;
+
+ total_len = len + sizeof(localhdr);
+
+ entry->length = total_len;
+ entry->refcount = 0;
+
+ for (i = 0; i < CONN_COUNT; i++) {
+ if (state[i].fd != fd) {
+ entry->refcount++;
+ state[i].expected[ state[i].tail ] = entry;
+ state[i].tail = (state[i].tail + 1) % MAXPENDING;
+ state[i].count_expected++;
+
+ assertFalse(state[i].tail == state[i].head,
+ "%s buffer wrap around on fd %d",
+ __func__,
+ state[i].fd);
+
+ if (CHATTY) {
+ printf("conn %2d added expected cnt %u length %zu\n",
+ i,
+ state[i].count_expected,
+ entry->length);
+ }
+ } else {
+ state[i].count_send++;
+
+ if (CHATTY) {
+ printf("conn %2d sent count %u\n", i, state[i].count_send);
+ }
+ }
+ }
+
+ res = write(fd, entry->buffer, entry->length);
+ assertTrue(res == entry->length, "%s write error %s\n", __func__, strerror(errno));
+}
+
+static int
+compare_sends(struct fdstate *s, uint8_t *buffer, size_t buffer_len)
+{
+ struct sendlist *expected = s->expected[ s->head ];
+ int res;
+
+ s->head = (s->head + 1) % MAXPENDING;
+
+ assertTrue(expected->length == buffer_len, "%s lengths do not match, expected %zu got %zu\n",
+ __func__, expected->length, buffer_len);
+
+ if (expected->length != buffer_len) {
+ return -1;
+ }
+
+ res = memcmp(expected->buffer, buffer, buffer_len);
+ assertTrue(res == 0, "%s buffers did not match\n", __func__);
+ if (res != 0) {
+ return -1;
+ }
+
+ assertTrue(expected->refcount > 0, "%s invalid refcount\n", __func__);
+
+ expected->refcount--;
+ if (expected->refcount == 0) {
+ memset(expected, 0, sizeof(struct sendlist));
+ parcMemory_Deallocate((void **) &expected);
+ }
+
+ return 0;
+}
+
+/*
+ * Create two connections to bent pipe and make sure they reflect
+ */
+LONGBOW_TEST_CASE(System, two_connections)
+{
+ struct fdstate state[CONN_COUNT];
+ fd_set fdset, readset;
+ int number_writes = 100;
+ int count_writes = 0;
+ int i;
+ struct timeval timeout = { 0, 10000 };
+ unsigned pending_expected = 0;
+
+ assertNotNull(system_bp, "%s running with null system_bp\n", __func__);
+
+ FD_ZERO(&fdset);
+ for (i = 0; i < CONN_COUNT; i++) {
+ memset(&state[i], 0, sizeof(struct fdstate));
+ state[i].fd = connect_to_bentpipe(local_name);
+ FD_SET(state[i].fd, &fdset);
+ }
+
+ sleep(1);
+
+ assertTrue(system_bp->conn_count == CONN_COUNT, "bp conn count wrong");
+
+ while (count_writes < number_writes || pending_expected > 0) {
+ int res;
+ memcpy(&readset, &fdset, sizeof(readset));
+
+ res = select(FD_SETSIZE, &readset, NULL, NULL, &timeout);
+ if (res < 0) {
+ perror("select");
+ abort();
+ }
+
+ if (res > 0) {
+ if (CHATTY) {
+ printf("%s got res %d\n", __func__, res);
+ }
+ for (i = 0; i < CONN_COUNT; i++) {
+ if (FD_ISSET(state[i].fd, &readset)) {
+ ssize_t res;
+ localhdr *hdr = (localhdr *) state[i].pbuff;
+
+ if (state[i].total_read_length == 0) {
+ size_t remaining = sizeof(localhdr) - state[i].current_read_length;
+ // we need to read a header
+ res = read(state[i].fd,
+ state[i].pbuff + state[i].current_read_length,
+ remaining);
+
+ assertFalse(res < 0, "%s got read error: %s", __func__, strerror(errno));
+
+ state[i].current_read_length += res;
+ if (state[i].current_read_length == sizeof(localhdr)) {
+ state[i].total_read_length = sizeof(localhdr) + hdr->length;
+
+ if (CHATTY) {
+ printf("%s conn %d fd %d set total length %zu\n",
+ __func__,
+ i,
+ state[i].fd,
+ state[i].total_read_length);
+ }
+ }
+ }
+
+ if (state[i].current_read_length < state[i].total_read_length) {
+ size_t remaining = state[i].total_read_length - state[i].current_read_length;
+ // we need to read a header
+ res = read(state[i].fd,
+ state[i].pbuff + state[i].current_read_length,
+ remaining);
+
+ assertFalse(res < 0, "%s got read error: %s", __func__, strerror(errno));
+ state[i].current_read_length += res;
+ }
+
+ if (state[i].current_read_length == state[i].total_read_length) {
+ // verify that it's the same as the top expected stack
+ res = compare_sends(&state[i], state[i].pbuff, state[i].total_read_length);
+
+ assertTrue(res == 0, "%s invalid receive compare\n", __func__);
+
+ state[i].count_recv++;
+ state[i].count_expected--;
+
+ if (CHATTY) {
+ printf("%s conn %d fd %d cnt_recv %u cnt_expected %u\n",
+ __func__,
+ i, state[i].fd, state[i].count_recv, state[i].count_expected);
+ }
+
+ // done with it
+ state[i].current_read_length = 0;
+ state[i].total_read_length = 0;
+ }
+ }
+ }
+ }
+
+ if ((random() % 4) == 0) {
+ // do a write
+ int out = random() % CONN_COUNT;
+
+ if (CHATTY) {
+ printf("%s sendbuffer for conn %d fd %d\n", __func__, out, state[out].fd);
+ }
+
+ sendbuffer(state[out].fd, state);
+ count_writes++;
+ }
+
+ pending_expected = 0;
+ for (i = 0; i < CONN_COUNT; i++) {
+ pending_expected += state[i].count_expected;
+ }
+ }
+
+ for (i = 0; i < CONN_COUNT; i++) {
+ printf("conn %2d fd %2d send %4u recv %4u\n",
+ i,
+ state[i].fd,
+ state[i].count_send,
+ state[i].count_recv);
+
+ assertTrue(state[i].count_recv == number_writes - state[i].count_send + 1,
+ "%s conn %d incorrect counts\n",
+ __func__);
+ close(state[i].fd);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(BentPipe);
+ exit(longBowMain(argc, argv, testRunner, NULL));
+}
diff --git a/libccnx-transport-rta/ccnx/transport/test_tools/traffic_tools.c b/libccnx-transport-rta/ccnx/transport/test_tools/traffic_tools.c
new file mode 100644
index 00000000..73b321e4
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/test_tools/traffic_tools.c
@@ -0,0 +1,292 @@
+/*
+ * 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_Memory.h>
+
+#include "traffic_tools.h"
+#include <ccnx/common/ccnx_NameSegmentNumber.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h>
+
+#include <ccnx/common/internal/ccnx_InterestDefault.h>
+
+#include <ccnx/api/control/cpi_ControlFacade.h>
+
+/**
+ * @function decode_last_component_as_segment
+ * @abstract Returns true is last name component is a segment, and returns the segment
+ * @discussion
+ * The outputSegment may be null, in which case this function is just a true/false for the
+ * last path segment being an object segment number.
+ *
+ * @param outputSegment is an output parameter of the segment number, if returns true. May be null.
+ * @return <#return#>
+ */
+bool
+trafficTools_GetObjectSegmentFromName(CCNxName *name, uint64_t *outputSegment)
+{
+ assertNotNull(name, "Name must be non-null");
+ bool success = false;
+ size_t segmentCount = ccnxName_GetSegmentCount(name);
+ if (segmentCount > 0) {
+ CCNxNameSegment *lastSegment = ccnxName_GetSegment(name, segmentCount - 1);
+ if (ccnxNameSegment_GetType(lastSegment) == CCNxNameLabelType_CHUNK) {
+ if (outputSegment) {
+ *outputSegment = ccnxNameSegmentNumber_Value(lastSegment);
+ }
+ success = true;
+ }
+ }
+ return success;
+}
+
+bool
+trafficTools_ReadAndVerifySegment(PARCEventQueue *queue, CCNxName *basename, uint64_t expected, PARCBuffer *expectedPayload)
+{
+ TransportMessage *test_tm;
+ CCNxName *test_name;
+ uint64_t segnum;
+ CCNxName *name_copy;
+
+ test_tm = rtaComponent_GetMessage(queue);
+ assertNotNull(test_tm, "got null transport message down the stack, expecting interest\n");
+
+ assertTrue(transportMessage_IsInterest(test_tm),
+ "Got wrong transport message pointer, is not an interest");
+
+ CCNxTlvDictionary *interestDictionary = transportMessage_GetDictionary(test_tm);
+ test_name = ccnxInterest_GetName(interestDictionary);
+
+ bool success = trafficTools_GetObjectSegmentFromName(test_name, &segnum);
+ assertTrue(success, "got error decoding last component as segnum: %s", ccnxName_ToString(test_name));
+ assertTrue(expected == segnum, "Got wrong segnum, expected %" PRIu64 ", got %" PRIu64 "\n",
+ expected, segnum);
+
+ name_copy = ccnxName_Copy(test_name);
+ ccnxName_Trim(name_copy, 1);
+ assertTrue(ccnxName_Compare(basename, name_copy) == 0,
+ "\nName '%s'\ndid not match\nexpected '%s'\nInterest name '%s'\n\n",
+ ccnxName_ToString(name_copy),
+ ccnxName_ToString(basename),
+ ccnxName_ToString(test_name));
+
+ ccnxName_Release(&name_copy);
+
+ if (expectedPayload != NULL) {
+ assertTrue(parcBuffer_Equals(expectedPayload, ccnxInterest_GetPayload(interestDictionary)),
+ "Expected the same Interest payload out as was sent in originally.");
+ }
+
+ transportMessage_Destroy(&test_tm);
+
+ return true;
+}
+
+CCNxContentObject *
+trafficTools_CreateSignedContentObject()
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/hello/dolly");
+ PARCBuffer *payload = parcBuffer_WrapCString("hello");
+
+ CCNxContentObject *result = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+
+ PARCBuffer *keyId = parcBuffer_WrapCString("keyhash");
+ PARCBuffer *sigbits = parcBuffer_WrapCString("siggybits");
+
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ parcBuffer_Release(&sigbits);
+
+ ccnxContentObject_SetSignature(result, keyId, signature, NULL);
+
+ parcBuffer_Release(&payload);
+ parcBuffer_Release(&keyId);
+ parcSignature_Release(&signature);
+ ccnxName_Release(&name);
+
+ return result;
+}
+
+CCNxContentObject *
+trafficTools_CreateContentObjectWithPayload(PARCBuffer *contents)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/hello/dolly");
+
+ CCNxContentObject *result = ccnxContentObject_CreateWithNameAndPayload(name, contents);
+
+ ccnxName_Release(&name);
+
+ return result;
+}
+
+TransportMessage *
+trafficTools_CreateTransportMessageWithSignedContentObject(RtaConnection *connection)
+{
+ CCNxContentObject *unsignedObject = trafficTools_CreateSignedContentObject();
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromContentObject(unsignedObject);
+ TransportMessage *tm = transportMessage_CreateFromDictionary(message);
+
+ transportMessage_SetInfo(tm, connection, NULL);
+
+ ccnxContentObject_Release(&unsignedObject);
+ ccnxMetaMessage_Release(&message);
+
+ return tm;
+}
+
+TransportMessage *
+trafficTools_CreateTransportMessageWithSignedContentObjectWithName(RtaConnection *connection, CCNxName *name, const char *keystorePath, const char *keystorePassword)
+{
+ PARCBuffer *payload = parcBuffer_WrapCString("hello");
+
+ CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ PARCBuffer *keyId = parcBuffer_WrapCString("hash of key");
+ PARCBuffer *sigbits = parcBuffer_WrapCString("sig bits");
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ parcBuffer_Release(&sigbits);
+
+ ccnxContentObject_SetSignature(contentObject, keyId, signature, NULL);
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromContentObject(contentObject);
+ TransportMessage *tm = transportMessage_CreateFromDictionary(message);
+ transportMessage_SetInfo(tm, connection, NULL);
+
+ ccnxMetaMessage_Release(&message);
+ ccnxContentObject_Release(&contentObject);
+ parcSignature_Release(&signature);
+ parcBuffer_Release(&keyId);
+ return tm;
+}
+
+CCNxInterest *
+trafficTools_CreateInterest(void)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/there/were/bells/on/the/hill");
+ CCNxInterest *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ return interest;
+}
+
+CCNxTlvDictionary *
+trafficTools_CreateDictionaryInterest(void)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/there/were/bells/on/the/hill");
+ CCNxTlvDictionary *interest = ccnxInterest_CreateSimple(name);
+ ccnxName_Release(&name);
+
+ return interest;
+}
+
+TransportMessage *
+trafficTools_CreateTransportMessageWithInterest(RtaConnection *connection)
+{
+ return trafficTools_CreateTransportMessageWithDictionaryInterest(connection, CCNxTlvDictionary_SchemaVersion_V1);
+}
+
+TransportMessage *
+trafficTools_CreateTransportMessageWithControlMessage(RtaConnection *connection)
+{
+ return trafficTools_CreateTransportMessageWithDictionaryControl(connection, CCNxTlvDictionary_SchemaVersion_V1);
+}
+
+TransportMessage *
+trafficTools_CreateTransportMessageWithRaw(RtaConnection *connection)
+{
+ return trafficTools_CreateTransportMessageWithDictionaryRaw(connection, CCNxTlvDictionary_SchemaVersion_V1);
+}
+
+TransportMessage *
+trafficTools_CreateTransportMessageWithDictionaryInterest(RtaConnection *connection, CCNxTlvDictionary_SchemaVersion schema)
+{
+ CCNxTlvDictionary *interest;
+ CCNxName *name = ccnxName_CreateFromCString("lci:/lost/in/space");
+
+ CCNxInterestInterface *impl = NULL;
+
+ switch (schema) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ impl = &CCNxInterestFacadeV1_Implementation;
+ break;
+
+ default:
+ trapIllegalValue(schema, "Unsupported schema version");
+ }
+
+ // impl should be set if we get here.
+ interest = ccnxInterest_CreateWithImpl(impl,
+ name,
+ CCNxInterestDefault_LifetimeMilliseconds,
+ NULL,
+ NULL,
+ CCNxInterestDefault_HopLimit);
+
+
+ TransportMessage *tm = transportMessage_CreateFromDictionary(interest);
+ ccnxTlvDictionary_Release(&interest);
+
+ transportMessage_SetInfo(tm, connection, NULL);
+ ccnxName_Release(&name);
+ return tm;
+}
+
+TransportMessage *
+trafficTools_CreateTransportMessageWithDictionaryRaw(RtaConnection *connection, unsigned schema)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(v1_interest_nameA));
+ parcBuffer_PutArray(buffer, sizeof(v1_interest_nameA), v1_interest_nameA);
+ parcBuffer_Flip(buffer);
+ CCNxTlvDictionary *wireformat = ccnxWireFormatMessage_FromInterestPacketType(schema, buffer);
+
+ TransportMessage *tm = transportMessage_CreateFromDictionary(wireformat);
+ ccnxTlvDictionary_Release(&wireformat);
+ parcBuffer_Release(&buffer);
+
+ transportMessage_SetInfo(tm, connection, NULL);
+ return tm;
+}
+
+TransportMessage *
+trafficTools_CreateTransportMessageWithDictionaryControl(RtaConnection *connection, unsigned schema)
+{
+ char *jsonstring = "{\"CPI_REQUEST\":{\"SEQUENCE\":22,\"REGISTER\":{\"PREFIX\":\"lci:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}";
+
+ PARCJSON *json = parcJSON_ParseString(jsonstring);
+ CCNxTlvDictionary *control = NULL;
+
+ switch (schema) {
+ case 1:
+ control = ccnxControlFacade_CreateCPI(json);
+
+ break;
+
+ default:
+ break;
+ }
+
+
+ TransportMessage *tm = transportMessage_CreateFromDictionary(control);
+ transportMessage_SetInfo(tm, connection, NULL);
+
+ parcJSON_Release(&json);
+ ccnxTlvDictionary_Release(&control);
+
+ return tm;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/test_tools/traffic_tools.h b/libccnx-transport-rta/ccnx/transport/test_tools/traffic_tools.h
new file mode 100644
index 00000000..09a8caf9
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/test_tools/traffic_tools.h
@@ -0,0 +1,284 @@
+/*
+ * 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 traffic_tools.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef Libccnx_traffic_generators_h
+#define Libccnx_traffic_generators_h
+
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/core/rta_ComponentQueue.h>
+
+#include <ccnx/common/ccnx_ContentObject.h>
+#include <ccnx/common/ccnx_Interest.h>
+
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+/**
+ * <#One Line Description#>
+ *
+ * Read the provided queue and verify the received message (Interest or Object)
+ * has the given basename (not including segment) and the provided segment number
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+bool trafficTools_ReadAndVerifySegment(PARCEventQueue *queue, CCNxName *basename,
+ uint64_t expectedSegnum, PARCBuffer *expectedPayload);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+bool trafficTools_GetObjectSegmentFromName(CCNxName *name, uint64_t *outputSegment);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CCNxContentObject *trafficTools_CreateSignedContentObject();
+
+/**
+ * Create a `CCNxUnsignedContentObject` with the given payload.
+ *
+ * The payload is contained within the given `PARCBuffer` from its position to its limit.
+ *
+ * @param [in] payload <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see PARCBuffer
+ */
+CCNxContentObject *trafficTools_CreateContentObjectWithPayload(PARCBuffer *payload);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+CCNxInterest *trafficTools_CreateInterest(void);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+TransportMessage *trafficTools_CreateTransportMessageWithControlMessage(RtaConnection *connection);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+TransportMessage *trafficTools_CreateTransportMessageWithInterest(RtaConnection *connection);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+TransportMessage *trafficTools_CreateTransportMessageWithSignedContentObject(RtaConnection *connection);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+TransportMessage *trafficTools_CreateTransportMessageWithSignedContentObjectWithName(RtaConnection *connection,
+ CCNxName *name, const char *keystorePath, const char *keystorePassword);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+TransportMessage *trafficTools_CreateTransportMessageWithRaw(RtaConnection *connection);
+
+
+/**
+ * Creates a Dictionary format RAW message
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+TransportMessage *trafficTools_CreateTransportMessageWithDictionaryRaw(RtaConnection *connection, unsigned schema);
+
+/**
+ * Creates a dictionary format Interest message
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+TransportMessage *trafficTools_CreateTransportMessageWithDictionaryInterest(RtaConnection *connection, unsigned schema);
+
+/**
+ * Creates a dictioary format Control message
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+TransportMessage *trafficTools_CreateTransportMessageWithDictionaryControl(RtaConnection *connection, unsigned schema);
+
+/**
+ * Creates an interest in Dictionary format
+ *
+ * Does not have a wire format
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxTlvDictionary *trafficTools_CreateDictionaryInterest(void);
+#endif // Libccnx_traffic_generators_h
diff --git a/libccnx-transport-rta/ccnx/transport/test_tools/write_packets.c b/libccnx-transport-rta/ccnx/transport/test_tools/write_packets.c
new file mode 100644
index 00000000..16c3e5ff
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/test_tools/write_packets.c
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+/**
+ * Utility function to write the test data to data files. The data files will be in a format
+ * you can use to import with "text2pcap". For example:
+ *
+ * text2pcap -u 9695,9695 file
+ *
+ * would add a fake UPD/IP/Ethernet header with UDP ports 9695 for source and destination
+ *
+ */
+
+#include <stdio.h>
+
+#include <ccnx/common/codec/schema_v0/testdata/testrig_truthSet.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_testrig_truthSet.h>
+
+/*
+ * typedef struct testrig_truth_table
+ * {
+ * const char * testname;
+ * uint8_t * packet;
+ * size_t length;
+ *
+ * TlvErrorCodes expectedError;
+ *
+ * // the array is terminated by a T_INVALID value
+ * // for "arrayIndexOrTypeKey"
+ * TruthTableEntry * entry;
+ * } TruthTable;
+ *
+ */
+
+static void
+writePacket(TruthTable *table)
+{
+ char filename[1024];
+ snprintf(filename, 1024, "%s.txt", table->testname);
+ FILE *fh = fopen(filename, "w+");
+ printf("name %s\n", filename);
+
+ int linewidth = 8;
+ for (int i = 0; i < table->length; i++) {
+ if ((i % linewidth) == 0) {
+ fprintf(fh, "\n%06X ", i);
+ }
+ fprintf(fh, "%02X ", table->packet[i]);
+ }
+ fprintf(fh, "\n");
+ fclose(fh);
+}
+
+static void
+loopTruthTable(TruthTable truthset[])
+{
+ for (int i = 0; truthset[i].packet != NULL; i++) {
+ writePacket(&truthset[i]);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ loopTruthTable(interests_truthSet);
+ loopTruthTable(contentObject_truthSet);
+ loopTruthTable(cpi_truthSet);
+
+ loopTruthTable(v1_interests_truthSet);
+ loopTruthTable(v1_contentObject_truthSet);
+ loopTruthTable(v1_cpi_truthSet);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_Command.c b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_Command.c
new file mode 100644
index 00000000..4e0e91d0
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_Command.c
@@ -0,0 +1,365 @@
+/*
+ * 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.
+ */
+
+/**
+ * Implements the single wrapper for commands sent over the command channel
+ *
+ */
+
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <ccnx/transport/transport_rta/commands/rta_Command.h>
+
+/*
+ * Internal definition of command types
+ */
+typedef enum {
+ RtaCommandType_Unknown = 0,
+ RtaCommandType_CreateProtocolStack,
+ RtaCommandType_OpenConnection,
+ RtaCommandType_CloseConnection,
+ RtaCommandType_DestroyProtocolStack,
+ RtaCommandType_ShutdownFramework,
+ RtaCommandType_TransmitStatistics,
+ RtaCommandType_Last
+} _RtaCommandType;
+
+struct rta_command {
+ _RtaCommandType type;
+
+ union {
+ RtaCommandCloseConnection *closeConnection;
+ RtaCommandOpenConnection *openConnection;
+ RtaCommandCreateProtocolStack *createStack;
+ RtaCommandDestroyProtocolStack *destroyStack;
+ RtaCommandTransmitStatistics *transmitStats;
+
+ // shutdown framework has no value it will be NULL
+ // Statistics has no value
+ void *noValue;
+ } value;
+};
+
+static struct commandtype_to_string {
+ _RtaCommandType type;
+ const char *string;
+} _RtaCommandTypeToString[] = {
+ { .type = RtaCommandType_Unknown, .string = "Unknown" },
+ { .type = RtaCommandType_CreateProtocolStack, .string = "CreateProtocolStack" },
+ { .type = RtaCommandType_OpenConnection, .string = "OpenConnection" },
+ { .type = RtaCommandType_CloseConnection, .string = "CloseConnection" },
+ { .type = RtaCommandType_DestroyProtocolStack, .string = "DestroyProtocolStack" },
+ { .type = RtaCommandType_ShutdownFramework, .string = "ShutdownFramework" },
+ { .type = RtaCommandType_TransmitStatistics, .string = "TransmitStatistics" },
+ { .type = RtaCommandType_Last, .string = NULL },
+};
+
+// ===============================
+// Internal API
+
+static void
+_rtaCommand_Destroy(RtaCommand **commandPtr)
+{
+ RtaCommand *command = *commandPtr;
+ switch (command->type) {
+ case RtaCommandType_ShutdownFramework:
+ // no inner-release needed
+ break;
+
+ case RtaCommandType_CreateProtocolStack:
+ rtaCommandCreateProtocolStack_Release(&command->value.createStack);
+ break;
+
+ case RtaCommandType_OpenConnection:
+ rtaCommandOpenConnection_Release(&command->value.openConnection);
+ break;
+
+ case RtaCommandType_CloseConnection:
+ rtaCommandCloseConnection_Release(&command->value.closeConnection);
+ break;
+
+ case RtaCommandType_DestroyProtocolStack:
+ rtaCommandDestroyProtocolStack_Release(&command->value.destroyStack);
+ break;
+
+ case RtaCommandType_TransmitStatistics:
+ rtaCommandTransmitStatistics_Release(&command->value.transmitStats);
+ break;
+
+ default:
+ trapIllegalValue(command->type, "Illegal command type %d", command->type);
+ break;
+ }
+}
+
+#ifdef Transport_DISABLE_VALIDATION
+# define _rtaCommand_OptionalAssertValid(_instance_)
+#else
+# define _rtaCommand_OptionalAssertValid(_instance_) _rtaCommand_AssertValid(_instance_)
+#endif
+
+static void
+_rtaCommand_AssertValid(const RtaCommand *command)
+{
+ assertNotNull(command, "RtaCommand must be non-null");
+ assertTrue(RtaCommandType_Unknown < command->type && command->type < RtaCommandType_Last,
+ "Invalid RtaCommand type, must be %d < type %d < %d",
+ RtaCommandType_Unknown,
+ command->type,
+ RtaCommandType_Last);
+
+ switch (command->type) {
+ case RtaCommandType_ShutdownFramework:
+ assertNull(command->value.noValue, "RtaCommand value must be null for ShutdownFramework or Statistics");
+ break;
+
+ case RtaCommandType_CreateProtocolStack:
+ assertNotNull(command->value.createStack, "RtaCommand createStack member must be non-null");
+ break;
+
+ case RtaCommandType_OpenConnection:
+ assertNotNull(command->value.openConnection, "RtaCommand openConnection member must be non-null");
+ break;
+
+ case RtaCommandType_CloseConnection:
+ assertNotNull(command->value.closeConnection, "RtaCommand closeConnection member must be non-null");
+ break;
+
+ case RtaCommandType_DestroyProtocolStack:
+ assertNotNull(command->value.destroyStack, "RtaCommand destroyStack member must be non-null");
+ break;
+
+ case RtaCommandType_TransmitStatistics:
+ assertNotNull(command->value.transmitStats, "RtaCommand transmitStats member must be non-null");
+ break;
+
+ default:
+ trapIllegalValue(command->type, "Illegal command type %d", command->type);
+ break;
+ }
+}
+
+parcObject_ExtendPARCObject(RtaCommand, _rtaCommand_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(rtaCommand, RtaCommand);
+
+parcObject_ImplementRelease(rtaCommand, RtaCommand);
+
+static RtaCommand *
+_rtaCommand_Allocate(_RtaCommandType type)
+{
+ RtaCommand *command = parcObject_CreateInstance(RtaCommand);
+ command->type = type;
+ return command;
+}
+
+static const char *
+_rtaCommand_TypeToString(const RtaCommand *command)
+{
+ for (int i = 0; _RtaCommandTypeToString[i].string != NULL; i++) {
+ if (_RtaCommandTypeToString[i].type == command->type) {
+ return _RtaCommandTypeToString[i].string;
+ }
+ }
+ trapUnexpectedState("Command is not a valid type: %d", command->type);
+}
+
+// ===============================
+// Public API
+
+void
+rtaCommand_Display(const RtaCommand *command, int indentation)
+{
+ _rtaCommand_OptionalAssertValid(command);
+
+ parcDisplayIndented_PrintLine(indentation, "RtaCommand type %s (%d) value pointer %p\n",
+ _rtaCommand_TypeToString(command), command->type, command->value);
+}
+
+/*
+ * Gets a reference to itself and puts it in the ring buffer
+ */
+bool
+rtaCommand_Write(const RtaCommand *command, PARCRingBuffer1x1 *commandRingBuffer)
+{
+ _rtaCommand_OptionalAssertValid(command);
+
+ RtaCommand *reference = rtaCommand_Acquire(command);
+
+ bool addedToRingBuffer = parcRingBuffer1x1_Put(commandRingBuffer, reference);
+
+ if (!addedToRingBuffer) {
+ // it was not stored in the ring, so we need to be responsible and release it
+ rtaCommand_Release(&reference);
+ }
+
+ return addedToRingBuffer;
+}
+
+RtaCommand *
+rtaCommand_Read(PARCRingBuffer1x1 *commandRingBuffer)
+{
+ RtaCommand *referenceFromRing = NULL;
+
+ bool fetchedReference = parcRingBuffer1x1_Get(commandRingBuffer, (void **) &referenceFromRing);
+ if (fetchedReference) {
+ return referenceFromRing;
+ }
+ return NULL;
+}
+
+// ======================
+// CLOSE CONNECTION
+
+bool
+rtaCommand_IsCloseConnection(const RtaCommand *command)
+{
+ _rtaCommand_OptionalAssertValid(command);
+ return (command->type == RtaCommandType_CloseConnection);
+}
+
+RtaCommand *
+rtaCommand_CreateCloseConnection(const RtaCommandCloseConnection *close)
+{
+ RtaCommand *command = _rtaCommand_Allocate(RtaCommandType_CloseConnection);
+ command->value.closeConnection = rtaCommandCloseConnection_Acquire(close);
+ return command;
+}
+
+const RtaCommandCloseConnection *
+rtaCommand_GetCloseConnection(const RtaCommand *command)
+{
+ assertTrue(rtaCommand_IsCloseConnection(command), "Command is not CloseConnection");
+ return command->value.closeConnection;
+}
+
+// ======================
+// OPEN CONNECTION
+
+bool
+rtaCommand_IsOpenConnection(const RtaCommand *command)
+{
+ _rtaCommand_OptionalAssertValid(command);
+ return (command->type == RtaCommandType_OpenConnection);
+}
+
+RtaCommand *
+rtaCommand_CreateOpenConnection(const RtaCommandOpenConnection *open)
+{
+ RtaCommand *command = _rtaCommand_Allocate(RtaCommandType_OpenConnection);
+ command->value.openConnection = rtaCommandOpenConnection_Acquire(open);
+ return command;
+}
+
+const RtaCommandOpenConnection *
+rtaCommand_GetOpenConnection(const RtaCommand *command)
+{
+ assertTrue(rtaCommand_IsOpenConnection(command), "Command is not OpenConnection");
+ return command->value.openConnection;
+}
+
+// ======================
+// CREATE STACK
+
+bool
+rtaCommand_IsCreateProtocolStack(const RtaCommand *command)
+{
+ _rtaCommand_OptionalAssertValid(command);
+ return (command->type == RtaCommandType_CreateProtocolStack);
+}
+
+RtaCommand *
+rtaCommand_CreateCreateProtocolStack(const RtaCommandCreateProtocolStack *createStack)
+{
+ RtaCommand *command = _rtaCommand_Allocate(RtaCommandType_CreateProtocolStack);
+ command->value.createStack = rtaCommandCreateProtocolStack_Acquire(createStack);
+ return command;
+}
+
+const RtaCommandCreateProtocolStack *
+rtaCommand_GetCreateProtocolStack(const RtaCommand *command)
+{
+ assertTrue(rtaCommand_IsCreateProtocolStack(command), "Command is not CreateProtocolStack");
+ return command->value.createStack;
+}
+
+bool
+rtaCommand_IsDestroyProtocolStack(const RtaCommand *command)
+{
+ _rtaCommand_OptionalAssertValid(command);
+ return (command->type == RtaCommandType_DestroyProtocolStack);
+}
+
+RtaCommand *
+rtaCommand_CreateDestroyProtocolStack(const RtaCommandDestroyProtocolStack *destroyStack)
+{
+ RtaCommand *command = _rtaCommand_Allocate(RtaCommandType_DestroyProtocolStack);
+ command->value.destroyStack = rtaCommandDestroyProtocolStack_Acquire(destroyStack);
+ return command;
+}
+
+const RtaCommandDestroyProtocolStack *
+rtaCommand_GetDestroyProtocolStack(const RtaCommand *command)
+{
+ assertTrue(rtaCommand_IsDestroyProtocolStack(command), "Command is not DestroyProtocolStack");
+ return command->value.destroyStack;
+}
+
+bool
+rtaCommand_IsShutdownFramework(const RtaCommand *command)
+{
+ _rtaCommand_OptionalAssertValid(command);
+ return (command->type == RtaCommandType_ShutdownFramework);
+}
+
+RtaCommand *
+rtaCommand_CreateShutdownFramework(void)
+{
+ RtaCommand *command = _rtaCommand_Allocate(RtaCommandType_ShutdownFramework);
+ command->value.noValue = NULL;
+ return command;
+}
+
+// no getter
+
+bool
+rtaCommand_IsTransmitStatistics(const RtaCommand *command)
+{
+ _rtaCommand_OptionalAssertValid(command);
+ return (command->type == RtaCommandType_TransmitStatistics);
+}
+
+RtaCommand *
+rtaCommand_CreateTransmitStatistics(const RtaCommandTransmitStatistics *transmitStats)
+{
+ RtaCommand *command = _rtaCommand_Allocate(RtaCommandType_TransmitStatistics);
+ command->value.transmitStats = rtaCommandTransmitStatistics_Acquire(transmitStats);
+ return command;
+}
+
+const RtaCommandTransmitStatistics *
+rtaCommand_GetTransmitStatistics(const RtaCommand *command)
+{
+ assertTrue(rtaCommand_IsTransmitStatistics(command), "Command is not TransmitStatistics");
+ return command->value.transmitStats;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_Command.h b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_Command.h
new file mode 100644
index 00000000..02973c54
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_Command.h
@@ -0,0 +1,619 @@
+/*
+ * 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_Command.h
+ * @brief Wraps individual commands and is written to/from a Ring Buffer
+ *
+ * The RtaCommand is the common wrapper for all the specific command types. It also supports functions to
+ * write it to a PARCRingBuffer and read from a one.
+ *
+ * The ShutdownFramework command is a little different than all the other commands. There are no parameters
+ * to this command, so there is no separate type for it. You can create an RtaCommand of this flavor and
+ * check for it (rtaCommand_IsShutdownFramework), but there is no Get function.
+ *
+ */
+#ifndef Libccnx_rta_Commands_h
+#define Libccnx_rta_Commands_h
+
+struct rta_command;
+typedef struct rta_command RtaCommand;
+
+#include <ccnx/transport/transport_rta/commands/rta_CommandCloseConnection.h>
+#include <ccnx/transport/transport_rta/commands/rta_CommandCreateProtocolStack.h>
+#include <ccnx/transport/transport_rta/commands/rta_CommandDestroyProtocolStack.h>
+#include <ccnx/transport/transport_rta/commands/rta_CommandOpenConnection.h>
+#include <ccnx/transport/transport_rta/commands/rta_CommandTransmitStatistics.h>
+
+#include <parc/concurrent/parc_RingBuffer_1x1.h>
+
+
+/**
+ * Writes a command to a Ring Buffer
+ *
+ * Creates a reference to the command and puts the reference on the ring buffer.
+ * The caller still owns their own reference to the command.
+ *
+ * This command does not involve a PARCNotifier. If using a notifier in conjunction
+ * with the ring buffer, the caller is reponsible for posting the notification after
+ * all ther writes are done.
+ *
+ * The function will not block. If the ring buffer is full, it will return false.
+ *
+ * @param [in] command The command to put (by reference) on the ring buffer.
+ * @param [in] commandRingBuffer The ring buffer to use
+ *
+ * @return true A reference was put on the ring buffer
+ * @return false Failed to put reference, likely because the ring buffer was full.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ *
+ * bool success = rtaCommand_Write(command, ring);
+ * if (!success) {
+ * // return error to user that we're backlogged
+ * }
+ *
+ * rtaCommand_Release(&command);
+ * }
+ * @endcode
+ */
+bool rtaCommand_Write(const RtaCommand *command, PARCRingBuffer1x1 *commandRingBuffer);
+
+/**
+ * Reads a command from a ring buffer
+ *
+ * If the buffer is empty, will return NULL.
+ *
+ * @param [in] commandRingBuffer The buffer to read
+ *
+ * @return non-null A valid command object
+ * @return null Could not read a whole command object
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(4, NULL);
+ * RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ *
+ * bool success = rtaCommand_Write(command, ring);
+ * assertTrue(success, "Failed to put command in to ring buffer");
+ *
+ * // We should now have two references
+ * assertTrue(parcObject_GetReferenceCount(command) == 2, "Wrong refernce count, got %zu expected %zu", parcObject_GetReferenceCount(command), 2);
+ *
+ * RtaCommand *test = rtaCommand_Read(ring);
+ * assertTrue(test == command, "Wrong pointers, got %p expected %p", (void *) test, (void *) command);
+ *
+ * rtaCommand_Release(&command);
+ * rtaCommand_Release(&test);
+ * parcRingBuffer1x1_Release(&ring);
+ * }
+ * @endcode
+ */
+RtaCommand *rtaCommand_Read(PARCRingBuffer1x1 *commandRingBuffer);
+
+/**
+ * Increase the number of references to a `RtaCommand`.
+ *
+ * Note that new `RtaCommand` is not created,
+ * only that the given `RtaCommand` reference count is incremented.
+ * Discard the reference by invoking `rtaCommand_Release`.
+ *
+ * @param [in] command The RtaCommand to reference.
+ *
+ * @return non-null A reference to `command`.
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ * RtaCommand *second = rtaCommand_Acquire(command);
+ *
+ * // release order does not matter
+ * rtaCommand_Release(&command);
+ * rtaCommand_Release(&second);
+ * }
+ * @endcode
+ */
+RtaCommand *rtaCommand_Acquire(const RtaCommand *command);
+
+/**
+ * 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] commandPtr A pointer to the object to release, will return NULL'd.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ * RtaCommand *second = rtaCommand_Acquire(command);
+ *
+ * // release order does not matter
+ * rtaCommand_Release(&command);
+ * rtaCommand_Release(&second);
+ * }
+ * @endcode
+ */
+void rtaCommand_Release(RtaCommand **commandPtr);
+
+/**
+ * Print a human readable representation of the given `RtaCommand`.
+ *
+ * @param [in] command A pointer to the instance to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ * rtaCommand_Display(command, 0);
+ * rtaCommand_Release(&command);
+ * }
+ * @endcode
+ *
+ */
+void rtaCommand_Display(const RtaCommand *command, int indentation);
+
+// ======================
+// CLOSE CONNECTION
+
+
+/**
+ * Tests if the RtaCommand is of type CloseConnection
+ *
+ * Tests if the RtaCommand is of type CloseConnection. This will also assert the
+ * RtaCommand invariants, so the RtaCommand object must be a properly constructed object.
+ *
+ * @param [in] command An allocated RtaCommand ojbect
+ *
+ * @return true The object is of type CloseConnection
+ * @return false The object is of some other type
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandCloseConnection *closeConnection = rtaCommandCloseConnection_Create(77);
+ * RtaCommand *command = rtaCommand_CreateCloseConnection(closeConnection);
+ * assertTrue(rtaCommand_IsCloseConnection(command), "Command is not CloseConnection");
+ * rtaCommand_Release(&command);
+ * rtaCommandCloseConnection_Release(&closeConnection);
+ * }
+ * @endcode
+ */
+bool rtaCommand_IsCloseConnection(const RtaCommand *command);
+
+/**
+ * Allocates and creates an RtaCommand object from a RtaCommandCloseConnection
+ *
+ * Allocates and creates an RtaCommand object from a RtaCommandCloseConnection
+ * by acquiring a reference to it and storing it in the RtaCommand. The caller
+ * may release their reference to `close` at any time.
+ *
+ * @param [in] close The specific command to make acquire a reference from.
+ *
+ * @return non-null A properly allocated and configured RtaCommand.
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandCloseConnection *closeConnection = rtaCommandCloseConnection_Create(77);
+ * RtaCommand *command = rtaCommand_CreateCloseConnection(closeConnection);
+ *
+ * // release order does not matter
+ * rtaCommand_Release(&command);
+ * rtaCommandCloseConnection_Release(&closeConnection);
+ * }
+ * @endcode
+ */
+RtaCommand *rtaCommand_CreateCloseConnection(const RtaCommandCloseConnection *close);
+
+/**
+ * Returns the internal RtaCommandCloseConnection object
+ *
+ * Returns the internal RtaCommandCloseConnection object, the user should not release it.
+ * The the RtaCommand is not of type CloseConnection, it will assert in its validation.
+ *
+ * @param [in] command The RtaCommand to query for the object.
+ *
+ * @return The RtaCommandCloseConnection object that constructed the RtaCommand.
+ *
+ * Example:
+ * @code
+ * RtaCommandCloseConnection *closeConnection = rtaCommandCloseConnection_Create(77);
+ * RtaCommand *command = rtaCommand_CreateCloseConnection(closeConnection);
+ *
+ * const RtaCommandCloseConnection *testValue = rtaCommand_GetCloseConnection(command);
+ * assertTrue(testValue == closeConnection, "Wrong pointer returned");
+ *
+ * rtaCommand_Release(&command);
+ * rtaCommandCloseConnection_Release(&closeConnection);
+ * @endcode
+ */
+const RtaCommandCloseConnection *rtaCommand_GetCloseConnection(const RtaCommand *command);
+
+// ======================
+// OPEN CONNECTION
+
+/**
+ * Tests if the RtaCommand is of type OpenConnection
+ *
+ * Tests if the RtaCommand is of type OpenConnection. This will also assert the
+ * RtaCommand invariants, so the RtaCommand object must be a properly constructed object.
+ *
+ * @param [in] command An allocated RtaCommand ojbect
+ *
+ * @return true The object is of type OpenConnection
+ * @return false The object is of some other type
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(111, 2341, 2450987, NULL);
+ * RtaCommand *command = rtaCommand_CreateOpenConnection(openConnection);
+ * assertTrue(rtaCommand_IsOpenConnection(command), "Command is not OpenConnection");
+ * rtaCommand_Release(&command);
+ * rtaCommandOpenConnection_Release(&openConnection);
+ * }
+ * @endcode
+ */
+bool rtaCommand_IsOpenConnection(const RtaCommand *command);
+
+/**
+ * Allocates and creates an RtaCommand object from a RtaCommandOpenConnection
+ *
+ * Allocates and creates an RtaCommand object from a RtaCommandOpenConnection
+ * by acquiring a reference to it and storing it in the RtaCommand. The caller
+ * may release their reference to `open` at any time.
+ *
+ * @param [in] open The specific command to make acquire a reference from.
+ *
+ * @return non-null A properly allocated and configured RtaCommand.
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(111, 2341, 2450987, NULL);
+ * RtaCommand *command = rtaCommand_CreateOpenConnection(openConnection);
+ *
+ * // release order does not matter
+ * rtaCommand_Release(&command);
+ * rtaCommandOpenConnection_Release(&openConnection);
+ * }
+ * @endcode
+ */
+RtaCommand *rtaCommand_CreateOpenConnection(const RtaCommandOpenConnection *open);
+
+/**
+ * Returns the internal RtaCommandOpenConnection object
+ *
+ * Returns the internal RtaCommandOpenConnection object, the user should not release it.
+ * The the RtaCommand is not of type CloseConnection, it will assert in its validation.
+ *
+ * @param [in] command The RtaCommand to query for the object.
+ *
+ * @return The RtaCommandOpenConnection object that constructed the RtaCommand.
+ *
+ * Example:
+ * @code
+ * RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(111, 2341, 2450987, NULL);
+ * RtaCommand *command = rtaCommand_CreateOpenConnection(openConnection);
+ *
+ * const RtaCommandOpenConnection *testValue = rtaCommand_GetOpenConnection(command);
+ * assertTrue(testValue == openConnection, "Wrong pointer returned");
+ *
+ * rtaCommand_Release(&command);
+ * rtaCommandOpenConnection_Release(&openConnection);
+ * @endcode
+ */
+const RtaCommandOpenConnection *rtaCommand_GetOpenConnection(const RtaCommand *command);
+
+// ======================
+// CREATE STACK
+
+/**
+ * Tests if the RtaCommand is of type CreateProtocolStack
+ *
+ * Tests if the RtaCommand is of type CreateProtocolStack. This will also assert the
+ * RtaCommand invariants, so the RtaCommand object must be a properly constructed object.
+ *
+ * @param [in] command An allocated RtaCommand ojbect
+ *
+ * @return true The object is of type CreateProtocolStack
+ * @return false The object is of some other type
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *config = ccnxStackConfig_Create();
+ * RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(111, config);
+ * RtaCommand *command = rtaCommand_CreateCreateProtocolStack(createStack);
+ * assertTrue(rtaCommand_IsCreateProtocolStack(command), "Command is not CreateProtocolStack");
+ * rtaCommand_Release(&command);
+ * rtaCommandCreateProtocolStack_Release(&createStack);
+ * ccnxStackConfig_Release(&config);
+ * }
+ * @endcode
+ */
+bool rtaCommand_IsCreateProtocolStack(const RtaCommand *command);
+
+/**
+ * Allocates and creates an RtaCommand object from a RtaCommandCreateProtocolStack
+ *
+ * Allocates and creates an RtaCommand object from a RtaCommandCreateProtocolStack
+ * by acquiring a reference to it and storing it in the RtaCommand. The caller
+ * may release their reference to `createStack` at any time.
+ *
+ * @param [in] createStack The specific command to make acquire a reference from.
+ *
+ * @return non-null A properly allocated and configured RtaCommand.
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *config = ccnxStackConfig_Create();
+ * RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(111, config);
+ * RtaCommand *command = rtaCommand_CreateCreateProtocolStack(createStack);
+ *
+ * // release order does not matter
+ * rtaCommand_Release(&command);
+ * rtaCommandCreateProtocolStack_Release(&createStack);
+ * ccnxStackConfig_Release(&config);
+ * }
+ * @endcode
+ */
+RtaCommand *rtaCommand_CreateCreateProtocolStack(const RtaCommandCreateProtocolStack *createStack);
+
+/**
+ * Returns the internal RtaCommandCreateProtocolStack object
+ *
+ * Returns the internal RtaCommandCreateProtocolStack object, the user should not release it.
+ * The the RtaCommand is not of type CloseConnection, it will assert in its validation.
+ *
+ * @param [in] command The RtaCommand to query for the object.
+ *
+ * @return The RtaCommandCreateProtocolStack object that constructed the RtaCommand.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *config = ccnxStackConfig_Create();
+ * RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(111, config);
+ * RtaCommand *command = rtaCommand_CreateCreateProtocolStack(createStack);
+ *
+ * const RtaCommandOpenConnection *testValue = rtaCommand_GetOpenConnection(command);
+ * assertTrue(testValue == createStack, "Wrong pointer returned");
+ *
+ * rtaCommand_Release(&command);
+ * rtaCommandCreateProtocolStack_Release(&createStack);
+ * ccnxStackConfig_Release(&config);
+ * }
+ * @endcode
+ */
+const RtaCommandCreateProtocolStack *rtaCommand_GetCreateProtocolStack(const RtaCommand *command);
+
+// ======================
+// DESTROY STACK
+
+/**
+ * Tests if the RtaCommand is of type DestroyProtocolStack
+ *
+ * Tests if the RtaCommand is of type DestroyProtocolStack. This will also assert the
+ * RtaCommand invariants, so the RtaCommand object must be a properly constructed object.
+ *
+ * @param [in] command An allocated RtaCommand ojbect
+ *
+ * @return true The object is of type DestroyProtocolStack
+ * @return false The object is of some other type
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(77);
+ * RtaCommand *command = rtaCommand_CreateDestroyProtocolStack(destroyStack);
+ * assertTrue(rtaCommand_IsDestroyProtocolStack(command), "Command is not DestroyProtocolStack");
+ * rtaCommand_Release(&command);
+ * rtaCommandDestroyProtocolStack_Release(&destroyStack);
+ * }
+ * @endcode
+ */
+bool rtaCommand_IsDestroyProtocolStack(const RtaCommand *command);
+
+/**
+ * Allocates and creates an RtaCommand object from a RtaCommandDestroyProtocolStack
+ *
+ * Allocates and creates an RtaCommand object from a RtaCommandDestroyProtocolStack
+ * by acquiring a reference to it and storing it in the RtaCommand. The caller
+ * may release their reference to `destroyStack` at any time.
+ *
+ * @param [in] destroyStack The specific command to make acquire a reference from.
+ *
+ * @return non-null A properly allocated and configured RtaCommand.
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(77);
+ * RtaCommand *command = rtaCommand_CreateDestroyProtocolStack(destroyStack);
+ *
+ * // release order does not matter
+ * rtaCommand_Release(&command);
+ * rtaCommandDestroyProtocolStack_Release(&destroyStack);
+ * }
+ * @endcode
+ */
+RtaCommand *rtaCommand_CreateDestroyProtocolStack(const RtaCommandDestroyProtocolStack *destroyStack);
+
+/**
+ * Returns the internal RtaCommandDestroyProtocolStack object
+ *
+ * Returns the internal RtaCommandDestroyProtocolStack object, the user should not release it.
+ * The the RtaCommand is not of type CloseConnection, it will assert in its validation.
+ *
+ * @param [in] command The RtaCommand to query for the object.
+ *
+ * @return The RtaCommandDestroyProtocolStack object that constructed the RtaCommand.
+ *
+ * Example:
+ * @code
+ * RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(77);
+ * RtaCommand *command = rtaCommand_CreateDestroyProtocolStack(destroyStack);
+ *
+ * const RtaCommandDestroyProtocolStack *testValue = rtaCommand_GetOpenConnection(command);
+ * assertTrue(testValue == destroyStack, "Wrong pointer returned");
+ *
+ * rtaCommand_Release(&command);
+ * rtaCommandDestroyProtocolStack_Release(&destroyStack);
+ * @endcode
+ */
+const RtaCommandDestroyProtocolStack *rtaCommand_GetDestroyProtocolStack(const RtaCommand *command);
+
+// ======================
+// SHUTDOWN FRAMEWORK
+
+/**
+ * Tests if the RtaCommand is of type ShutdownFramework
+ *
+ * Tests if the RtaCommand is of type ShutdownFramework. This will also assert the
+ * RtaCommand invariants, so the RtaCommand object must be a properly constructed object.
+ *
+ * The ShutdownFramework command has no parameters, so there is no rtaCommand_GetShutdownFramework() function.
+ *
+ * @param [in] command An allocated RtaCommand ojbect
+ *
+ * @return true The object is of type ShutdownFramework
+ * @return false The object is of some other type
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ * assertTrue(rtaCommand_IsShutdownFramework(command), "Command is not shutdown framework");
+ * rtaCommand_Release(&command);
+ * }
+ * @endcode
+ */
+bool rtaCommand_IsShutdownFramework(const RtaCommand *command);
+
+/**
+ * Allocates and creates an RtaCommand object of type ShutdownFramework.
+ *
+ * Allocates and creates an RtaCommand object of type ShutdownFramework.
+ * There are no parameters to ShutdownFramework, so there is no underlying type.
+ *
+ * @return non-null A properly allocated and configured RtaCommand.
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ * rtaCommand_Release(&command);
+ * }
+ * @endcode
+ */
+RtaCommand *rtaCommand_CreateShutdownFramework(void);
+
+// ======================
+// TRANSMIT STATS
+
+/**
+ * Tests if the RtaCommand is of type TransmitStatistics
+ *
+ * Tests if the RtaCommand is of type TransmitStatistics. This will also assert the
+ * RtaCommand invariants, so the RtaCommand object must be a properly constructed object.
+ *
+ * @param [in] command An allocated RtaCommand ojbect
+ *
+ * @return true The object is of type TransmitStatistics
+ * @return false The object is of some other type
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandTransmitStatistics *transmitStats = rtaCommandTransmitStatistics_Create((struct timeval) { 1, 2 }, "filename");
+ * RtaCommand *command = rtaCommand_CreateTransmitStatistics(transmitStats);
+ * assertTrue(rtaCommand_IsTransmitStatistics(command), "Command is not TransmitStatistics");
+ * rtaCommand_Release(&command);
+ * rtaCommandTransmitStatistics_Release(&transmitStats);
+ * }
+ * @endcode
+ */
+bool rtaCommand_IsTransmitStatistics(const RtaCommand *command);
+
+/**
+ * Allocates and creates an RtaCommand object from a RtaCommandTransmitStatistics
+ *
+ * Allocates and creates an RtaCommand object from a RtaCommandTransmitStatistics
+ * by acquiring a reference to it and storing it in the RtaCommand. The caller
+ * may release their reference to `transmitStats` at any time.
+ *
+ * @param [in] transmitStats The specific command to make acquire a reference from.
+ *
+ * @return non-null A properly allocated and configured RtaCommand.
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandTransmitStatistics *transmitStats = rtaCommandTransmitStatistics_Create((struct timeval) { 1, 2 }, "filename");
+ * RtaCommand *command = rtaCommand_CreateTransmitStatistics(transmitStats);
+ *
+ * // release order does not matter
+ * rtaCommand_Release(&command);
+ * rtaCommandTransmitStatistics_Release(&transmitStats);
+ * }
+ * @endcode
+ */
+RtaCommand *rtaCommand_CreateTransmitStatistics(const RtaCommandTransmitStatistics *transmitStats);
+
+/**
+ * Returns the internal RtaCommandTransmitStatistics object
+ *
+ * Returns the internal RtaCommandTransmitStatistics object, the user should not release it.
+ * The the RtaCommand is not of type CloseConnection, it will assert in its validation.
+ *
+ * @param [in] command The RtaCommand to query for the object.
+ *
+ * @return The RtaCommandTransmitStatistics object that constructed the RtaCommand.
+ *
+ * Example:
+ * @code
+ * RtaCommandTransmitStatistics *transmitStats = rtaCommandTransmitStatistics_Create((struct timeval) { 1, 2 }, "filename");
+ * RtaCommand *command = rtaCommand_CreateTransmitStatistics(transmitStats);
+ *
+ * const RtaCommandDestroyProtocolStack *testValue = rtaCommand_GetOpenConnection(command);
+ * assertTrue(testValue == destroyStack, "Wrong pointer returned");
+ *
+ * rtaCommand_Release(&command);
+ * rtaCommandTransmitStatistics_Release(&transmitStats);
+ * @endcode
+ */
+const RtaCommandTransmitStatistics *rtaCommand_GetTransmitStatistics(const RtaCommand *command);
+#endif // Libccnx_rta_Commands_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCloseConnection.c b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCloseConnection.c
new file mode 100644
index 00000000..d5c092e8
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCloseConnection.c
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+/**
+ *
+ * Implements the RtaCommandCloseConnection object. Only has to pass one argument, the apiSocket number,
+ * to identify which connection to close.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <ccnx/transport/transport_rta/commands/rta_CommandCloseConnection.h>
+
+struct rta_command_closeconnection {
+ int apiNotifierFd;
+};
+
+parcObject_ExtendPARCObject(RtaCommandCloseConnection, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(rtaCommandCloseConnection, RtaCommandCloseConnection);
+
+parcObject_ImplementRelease(rtaCommandCloseConnection, RtaCommandCloseConnection);
+
+RtaCommandCloseConnection *
+rtaCommandCloseConnection_Create(int apiNotifierFd)
+{
+ RtaCommandCloseConnection *closeConnection = parcObject_CreateInstance(RtaCommandCloseConnection);
+ closeConnection->apiNotifierFd = apiNotifierFd;
+ return closeConnection;
+}
+
+int
+rtaCommandCloseConnection_GetApiNotifierFd(const RtaCommandCloseConnection *closeConnection)
+{
+ assertNotNull(closeConnection, "Parameter closeConnection must be non-null");
+ return closeConnection->apiNotifierFd;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCloseConnection.h b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCloseConnection.h
new file mode 100644
index 00000000..4c46d831
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCloseConnection.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.
+ */
+
+/**
+ * @file rta_CommandCloseConnection.h
+ * @brief Represents a command to close a connection
+ *
+ * Used to construct an RtaCommand object that is passed to rtaTransport_PassCommand() or _rtaTransport_SendCommandToFramework()
+ * to send a command from the API's thread of execution to the Transport's thread of execution.
+ *
+ */
+#ifndef Libccnx_rta_CommandCloseConnection_h
+#define Libccnx_rta_CommandCloseConnection_h
+
+struct rta_command_closeconnection;
+typedef struct rta_command_closeconnection RtaCommandCloseConnection;
+
+/**
+ * Creates a CloseConnection command object
+ *
+ * Creates a CloseConnection command object used to signal the RTA framework to
+ * close a specified connection. The user passes its socket number to the close
+ * command to signify which connection.
+ *
+ * The apiNotifierFd number must correspond to the apiSocket number used in rtaCommandOpenConnection().
+ *
+ * @param [in] apiNotifierFd The descriptor number used by the API
+ *
+ * @return non-null An allocated object
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * void foo(RTATransport *transport)
+ * {
+ * #define API_SIDE 0
+ * #define TRANSPORT_SIDE 1
+ *
+ * int pair[2];
+ * socketpair(AF_LOCAL, SOCK_STREAM, 0, pair);
+ * PARCJSON *config = createConnectionConfig();
+ *
+ * RtaCommandOpenConnection *openCommand = rtaCommandOpenConnection_Create(6, pair[API_SIDE], pair[TRANSPORT_SIDE], config);
+ * RtaCommand *command = rtaCommand_CreateOpenConnection(openCommand);
+ * _rtaTransport_SendCommandToFramework(transport, command);
+ * rtaCommand_Release(&command);
+ * rtaCommandOpenConnection_Release(&openCommand);
+ *
+ * // ... do work ...
+ *
+ * RtaCommandCloseConnection *closeCommand = rtaCommandCloseConnection_Create(pair[API_SIDE]);
+ * command = rtaCommand_CreateCloseConnection(openCommand);
+ * _rtaTransport_SendCommandToFramework(transport, command);
+ * rtaCommand_Release(&command);
+ * rtaCommandCloseConnection_Release(&closeCommand);
+ * }
+ * @endcode
+ */
+RtaCommandCloseConnection *rtaCommandCloseConnection_Create(int apiNotifierFd);
+
+/**
+ * Increase the number of references to a `RtaCommandCloseConnection`.
+ *
+ * Note that new `RtaCommandCloseConnection` is not created,
+ * only that the given `RtaCommandCloseConnection` reference count is incremented.
+ * Discard the reference by invoking `rtaCommandCloseConnection_Release`.
+ *
+ * @param [in] closeConnection The RtaCommandCloseConnection to reference.
+ *
+ * @return non-null A reference to `closeConnection`.
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandCloseConnection *closeConnection = rtaCommandCloseConnection_Create(pair[API_SIDE]);
+ * RtaCommandCloseConnection *second = rtaCommandCloseConnection_Acquire(closeConnection);
+ *
+ * // release order does not matter
+ * rtaCommandCloseConnection_Release(&closeConnection);
+ * rtaCommandCloseConnection_Release(&second);
+ * }
+ * @endcode
+ */
+RtaCommandCloseConnection *rtaCommandCloseConnection_Acquire(const RtaCommandCloseConnection *closeConnection);
+
+/**
+ * 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] closePtr A pointer to the object to release, will return NULL'd.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandCloseConnection *closeCommand = rtaCommandCloseConnection_Create(pair[API_SIDE]);
+ * RtaCommand *command = rtaCommand_CreateCloseConnection(openCommand);
+ * _rtaTransport_SendCommandToFramework(transport, command);
+ * rtaCommand_Release(&command);
+ * rtaCommandCloseConnection_Release(&closeCommand);
+ * }
+ * @endcode
+ */
+void rtaCommandCloseConnection_Release(RtaCommandCloseConnection **closePtr);
+
+/**
+ * Returns the API notifier descriptor of the close command
+ *
+ * Returns the apiNotifierFd parameter.
+ *
+ * @param [in] closeConnection An allocated RtaCommandCloseConnection
+ *
+ * @return integer The value passed to rtaCommandCloseConnection_Create().
+ *
+ * Example:
+ * @code
+ * {
+ * int apiNotifierFd = 7;
+ * RtaCommandCloseConnection *closeCommand = rtaCommandCloseConnection_Create(apiNotifierFd);
+ * int testValue = rtaCommandCloseConnection_GetApiNotifierFd(closeCommand);
+ * assertTrue(testValue == apiNotifierFd, "Wrong value got %d expected %d", testValue, apiNotifierFd);
+ * rtaCommandCloseConnection_Release(&closeCommand);
+ * }
+ * @endcode
+ */
+int rtaCommandCloseConnection_GetApiNotifierFd(const RtaCommandCloseConnection *closeConnection);
+#endif // Libccnx_rta_CommandCloseConnection_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCreateProtocolStack.c b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCreateProtocolStack.c
new file mode 100644
index 00000000..fb5ecd9a
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCreateProtocolStack.c
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+/**
+ *
+ * Implements the RtaCommandCreateProtocolStack object which signals to RTA Framework to open a new connection
+ * with the given configuration.
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <ccnx/transport/transport_rta/commands/rta_CommandCreateProtocolStack.h>
+
+struct rta_command_createprotocolstack {
+ int stackId;
+ CCNxStackConfig *config;
+};
+
+static void
+_rtaCommandCreateProtocolStack_Destroy(RtaCommandCreateProtocolStack **openConnectionPtr)
+{
+ RtaCommandCreateProtocolStack *openConnection = *openConnectionPtr;
+
+ if (openConnection->config) {
+ ccnxStackConfig_Release(&openConnection->config);
+ }
+}
+
+parcObject_ExtendPARCObject(RtaCommandCreateProtocolStack, _rtaCommandCreateProtocolStack_Destroy,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(rtaCommandCreateProtocolStack, RtaCommandCreateProtocolStack);
+
+parcObject_ImplementRelease(rtaCommandCreateProtocolStack, RtaCommandCreateProtocolStack);
+
+RtaCommandCreateProtocolStack *
+rtaCommandCreateProtocolStack_Create(int stackId, CCNxStackConfig *config)
+{
+ RtaCommandCreateProtocolStack *createStack = parcObject_CreateInstance(RtaCommandCreateProtocolStack);
+ createStack->stackId = stackId;
+ createStack->config = ccnxStackConfig_Copy(config);
+ return createStack;
+}
+
+const char *
+rtaCommandCreateProtocolStack_AssessValidity(const RtaCommandCreateProtocolStack *instance)
+{
+ char *result = NULL;
+
+ if (instance != NULL) {
+ if (ccnxStackConfig_IsValid(instance->config)) {
+ result = NULL;
+ } else {
+ result = "CCNxStackConfig instance is invalid";
+ }
+ } else {
+ result = "Instance cannot be NULL";
+ }
+
+ return result;
+}
+
+bool
+rtaCommandCreateProtocolStack_IsValid(const RtaCommandCreateProtocolStack *instance)
+{
+ const char *assessment = rtaCommandCreateProtocolStack_AssessValidity(instance);
+ return assessment == NULL;
+}
+
+void
+rtaCommandCreateProtocolStack_AssertValid(const RtaCommandCreateProtocolStack *instance)
+{
+ const char *assessment = rtaCommandCreateProtocolStack_AssessValidity(instance);
+ trapIllegalValueIf(assessment != NULL, "%s", assessment);
+}
+
+int
+rtaCommandCreateProtocolStack_GetStackId(const RtaCommandCreateProtocolStack *createStack)
+{
+ assertNotNull(createStack, "Parameter createStack must be non-null");
+ return createStack->stackId;
+}
+
+CCNxStackConfig *
+rtaCommandCreateProtocolStack_GetStackConfig(const RtaCommandCreateProtocolStack *createStack)
+{
+ return createStack->config;
+}
+
+PARCJSON *
+rtaCommandCreateProtocolStack_GetConfig(const RtaCommandCreateProtocolStack *createStack)
+{
+ assertNotNull(createStack, "Parameter createStack must be non-null");
+ return ccnxStackConfig_GetJson(createStack->config);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCreateProtocolStack.h b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCreateProtocolStack.h
new file mode 100644
index 00000000..a14f651c
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandCreateProtocolStack.h
@@ -0,0 +1,274 @@
+/*
+ * 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_CommandCreateProtocolStack.h
+ * @brief Represents a command to create a protocol stack
+ *
+ * Used to construct an RtaCommand object that is passed to rtaTransport_PassCommand() or _rtaTransport_SendCommandToFramework()
+ * to send a command from the API's thread of execution to the Transport's thread of execution.
+ *
+ */
+#ifndef Libccnx_rta_CommandCreateProtocolStack_h
+#define Libccnx_rta_CommandCreateProtocolStack_h
+
+struct rta_command_createprotocolstack;
+typedef struct rta_command_createprotocolstack RtaCommandCreateProtocolStack;
+
+
+#include <ccnx/transport/common/ccnx_StackConfig.h>
+
+/**
+ * Creates a CreateProtocolStack command object
+ *
+ * Creates a CreateProtocolStack command object used to signal the RTA framework to
+ * create a new Protocol Stack with the specified stackId and configuration. The caller is
+ * responsible for ensuring that the stackId is unique among existing stacks (the framework might
+ * assert an error for duplicates). Note that the check for a unique stack ID is only done
+ * once the RtaCommandCreateProtocolStack is passed to the RtaFramework, not on creation
+ * of this object.
+ *
+ * @param [in] stackId The new (unique) ID for the stack to create
+ * @param [in] config the JSON representation of the stack configuration
+ *
+ * @return non-null An allocated object
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * void
+ * foo(RTATransport *transport)
+ * {
+ * int stackId = nextStackIdNumber();
+ *
+ * CCNxStackConfig *config = ccnxStackConfig_Create();
+ * RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+ * RtaCommand *command = rtaCommand_CreateCreateProtocolStack(createStack);
+ * _rtaTransport_SendCommandToFramework(transport, command);
+ * rtaCommand_Release(&command);
+ * rtaCommandCreateProtocolStack_Release(&createStack);
+ *
+ * // ... do work ...
+ *
+ * RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(stackId);
+ * command = rtaCommand_CreateDestroyProtocolStack(destroyStack);
+ * _rtaTransport_SendCommandToFramework(transport, command);
+ * rtaCommand_Release(&command);
+ * rtaCommandDestroyProtocolStack(&destroyStack);
+ * ccnxStackConfig_Release(&config);
+ * }
+ * @endcode
+ */
+RtaCommandCreateProtocolStack *rtaCommandCreateProtocolStack_Create(int stackId, CCNxStackConfig *config);
+
+/**
+ * Increase the number of references to a `RtaCommandCreateProtocolStack`.
+ *
+ * Note that new `RtaCommandCreateProtocolStack` is not created,
+ * only that the given `RtaCommandCreateProtocolStack` reference count is incremented.
+ * Discard the reference by invoking `rtaCommandCreateProtocolStack_Release`.
+ *
+ * @param [in] createStack The RtaCommandCreateProtocolStack to reference.
+ *
+ * @return non-null A reference to `createStack`.
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *config = ccnxStackConfig_Create();
+ * RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+ * RtaCommandCreateProtocolStack *second = rtaCommandCreateProtocolStack_Acquire(createStack);
+ *
+ * // release order does not matter
+ * rtaCommandCreateProtocolStack_Release(&createStack);
+ * rtaCommandCreateProtocolStack_Release(&second);
+ * ccnxStackConfig_Release(&config);
+ * }
+ * @endcode
+ */
+RtaCommandCreateProtocolStack *rtaCommandCreateProtocolStack_Acquire(const RtaCommandCreateProtocolStack *createStack);
+
+/**
+ * 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] closePtr A pointer to the object to release, will return NULL'd.
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *config = ccnxStackConfig_Create();
+ * RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+ * RtaCommand *command = rtaCommand_CreateCreateProtocolStack(createStack);
+ * _rtaTransport_SendCommandToFramework(transport, command);
+ * rtaCommand_Release(&command);
+ * rtaCommandCreateProtocolStack_Release(&createStack);
+ * ccnxStackConfig_Release(&config);
+ * }
+ * @endcode
+ */
+void rtaCommandCreateProtocolStack_Release(RtaCommandCreateProtocolStack **createStackPtr);
+
+/**
+ * Returns the Stack ID of the create stack command
+ *
+ * Returns the Stack ID parameter.
+ *
+ * @param [in] createStack An allocated RtaCommandCreateProtocolStack
+ *
+ * @return integer The value passed to rtaCommandCreateProtocolStack_Create().
+ *
+ * Example:
+ * @code
+ * {
+ * int stackId = 7;
+ * CCNxStackConfig *config = ccnxStackConfig_Create();
+ * RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+ * int testValue = rtaCommandCreateProtocolStack_GetStackId(createStack);
+ * assertTrue(testValue == stackId, "Wrong value got %d expected %d", testValue, stackId);
+ * rtaCommandCreateProtocolStack_Release(&createStack);
+ * ccnxStackConfig_Release(&config);
+ * }
+ * @endcode
+ */
+int rtaCommandCreateProtocolStack_GetStackId(const RtaCommandCreateProtocolStack *createStack);
+
+/**
+ * Get the CCNxStackConfig used by the given `RtaCommandCreateProtocolStack` instance.
+ *
+ * @param [in] createStack A pointer to a valid `RtaCommandCreateProtocolStack` instance.
+ *
+ * @return A pointer to the CCNxStackConfig used by the given `RtaCommandCreateProtocolStack` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * int stackId = 7;
+ *
+ * CCNxStackConfig *config = ccnxStackConfig_Create();
+ * RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+ *
+ * CCNxStackConfig *config = rtaCommandCreateProtocolStack_GetStackConfig(createStack);
+ *
+ * rtaCommandCreateProtocolStack_Release(&createStack);
+ *
+ * ccnxStackConfig_Release(&config);
+ * }
+ * @endcode
+ */
+CCNxStackConfig *rtaCommandCreateProtocolStack_GetStackConfig(const RtaCommandCreateProtocolStack *createStack);
+
+/**
+ * Returns the PARCJSON stack configuration of the create stack command
+ *
+ * Returns the JSON representation of the stack configuration.
+ *
+ * @param [in] createStack An allocated RtaCommandCreateProtocolStack
+ *
+ * @return The value passed to rtaCommandCreateProtocolStack_Create().
+ *
+ * Example:
+ * @code
+ * {
+ * int stackId = 7;
+ *
+ * CCNxStackConfig *config = ccnxStackConfig_Create();
+ * RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+ *
+ * PARCJSON *testValue = rtaCommandCreateProtocolStack_GetConfig(createStack);
+ * assertTrue(ccnxJson_Equals(config, testValue), "Wrong value");
+ * rtaCommandCreateProtocolStack_Release(&createStack);
+ *
+ * ccnxStackConfig_Release(&config);
+ * }
+ * @endcode
+ */
+PARCJSON *rtaCommandCreateProtocolStack_GetConfig(const RtaCommandCreateProtocolStack *createStack);
+
+/**
+ * Derive an explanation for why a RtaCommandCreateProtocolStack instance is invalid.
+ *
+ * Returns either a nul-terminated C string containing a human-readable explanation,
+ * or NULL which indicates the instance is valid.
+ *
+ * @param [in] instance A pointer to a `RtaCommandCreateProtocolStack` instance.
+ *
+ * @return NULL The instance is valid.
+ * @return non-NULL A nul-terminated C string containing an explanation.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandCreateProtocolStack *instance = rtaCommandCreateProtocolStack_Create(...);
+ *
+ * if (rtaCommandCreateProtocolStack_IsValid(instance)) {
+ * printf("Instance is valid.\n");
+ * }
+ * }
+ * @endcode
+ */
+const char *rtaCommandCreateProtocolStack_AssessValidity(const RtaCommandCreateProtocolStack *instance);
+
+/**
+ * Determine if an instance of `RtaCommandCreateProtocolStack` 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] instance A pointer to a `RtaCommandCreateProtocolStack` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandCreateProtocolStack *instance = rtaCommandCreateProtocolStack_Create(...);
+ *
+ * if (rtaCommandCreateProtocolStack_IsValid(instance)) {
+ * printf("Instance is valid.\n");
+ * }
+ * }
+ * @endcode
+ */
+bool rtaCommandCreateProtocolStack_IsValid(const RtaCommandCreateProtocolStack *instance);
+
+/**
+ * Assert that the given `RtaCommandCreateProtocolStack` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid RtaCommandCreateProtocolStack instance.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandCreateProtocolStack *a = rtaCommandCreateProtocolStack_Create();
+ *
+ * rtaCommandCreateProtocolStack_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * rtaCommandCreateProtocolStack_Release(&b);
+ * }
+ * @endcode
+ */
+void rtaCommandCreateProtocolStack_AssertValid(const RtaCommandCreateProtocolStack *instance);
+#endif // Libccnx_rta_CommandCreateProtocolStack_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandDestroyProtocolStack.c b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandDestroyProtocolStack.c
new file mode 100644
index 00000000..4ce4321f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandDestroyProtocolStack.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.
+ */
+
+/**
+ *
+ * Implements the RtaCommandDestroyProtocolStack object which signals to RTA Framework to open a new connection
+ * with the given configuration.
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <ccnx/transport/transport_rta/commands/rta_CommandDestroyProtocolStack.h>
+
+struct rta_command_destroyprotocolstack {
+ int stackId;
+};
+
+parcObject_ExtendPARCObject(RtaCommandDestroyProtocolStack,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(rtaCommandDestroyProtocolStack, RtaCommandDestroyProtocolStack);
+
+parcObject_ImplementRelease(rtaCommandDestroyProtocolStack, RtaCommandDestroyProtocolStack);
+
+// ======= Public API
+
+RtaCommandDestroyProtocolStack *
+rtaCommandDestroyProtocolStack_Create(int stackId)
+{
+ RtaCommandDestroyProtocolStack *createStack = parcObject_CreateInstance(RtaCommandDestroyProtocolStack);
+ createStack->stackId = stackId;
+ return createStack;
+}
+
+
+int
+rtaCommandDestroyProtocolStack_GetStackId(const RtaCommandDestroyProtocolStack *destroyStack)
+{
+ assertNotNull(destroyStack, "Parameter destroyStack must be non-null");
+ return destroyStack->stackId;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandDestroyProtocolStack.h b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandDestroyProtocolStack.h
new file mode 100644
index 00000000..feecfac9
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandDestroyProtocolStack.h
@@ -0,0 +1,141 @@
+/*
+ * 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_CommandDestroyProtocolStack.h
+ * @brief Represents a command to destroy a protocol stack
+ *
+ * Used to construct an RtaCommand object that is passed to rtaTransport_PassCommand() or _rtaTransport_SendCommandToFramework()
+ * to send a command from the API's thread of execution to the Transport's thread of execution.
+ *
+ */
+#ifndef Libccnx_rta_CommandDestroyProtocolStack_h
+#define Libccnx_rta_CommandDestroyProtocolStack_h
+
+struct rta_command_destroyprotocolstack;
+typedef struct rta_command_destroyprotocolstack RtaCommandDestroyProtocolStack;
+
+/**
+ * Creates a DestroyProtocolStack command object
+ *
+ * Creates a DestroyProtocolStack command object used to signal the RTA framework to
+ * destroy a protocol stack and all connections in it.
+ *
+ * @param [in] stackId The ID used to create the protocol stack.
+ *
+ * @return non-null An allocated object
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * void foo(RTATransport *transport)
+ * {
+ * int stackId = nextStackIdNumber();
+ * CCNxStackConfig *config = ccnxStackConfig_Create();
+ *
+ * RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+ * RtaCommand *command = rtaCommand_CreateCreateProtocolStack(createStack);
+ * _rtaTransport_SendCommandToFramework(transport, command);
+ * rtaCommand_Release(&command);
+ * rtaCommandCreateProtocolStack_Release(&createStack);
+ *
+ * // ... do work ...
+ *
+ * RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(stackId);
+ * command = rtaCommand_CreateDestroyProtocolStack(destroyStack);
+ * _rtaTransport_SendCommandToFramework(transport, command);
+ * rtaCommand_Release(&command);
+ * rtaCommandDestroyProtocolStack_Release(&destroyStack);
+ * ccnxStackConfig_Release(&config);
+ * }
+ * @endcode
+ */
+RtaCommandDestroyProtocolStack *rtaCommandDestroyProtocolStack_Create(int stackId);
+
+/**
+ * Increase the number of references to a `RtaCommandDestroyProtocolStack`.
+ *
+ * Note that new `RtaCommandDestroyProtocolStack` is not created,
+ * only that the given `RtaCommandDestroyProtocolStack` reference count is incremented.
+ * Discard the reference by invoking `rtaCommandDestroyProtocolStack_Release`.
+ *
+ * @param [in] destroyStack The RtaCommandDestroyProtocolStack to reference.
+ *
+ * @return non-null A reference to `destroyStack`.
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * CCNxStackConfig *config = ccnxStackConfig_Create();
+ * RtaCommandDestroyProtocolStack *destroyStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+ * RtaCommandDestroyProtocolStack *second = rtaCommandDestroyProtocolStack_Acquire(destroyStack);
+ *
+ * // release order does not matter
+ * rtaCommandDestroyProtocolStack_Release(&destroyStack);
+ * rtaCommandDestroyProtocolStack_Release(&second);
+ * ccnxStackConfig_Release(&config);
+ * }
+ * @endcode
+ */
+RtaCommandDestroyProtocolStack *rtaCommandDestroyProtocolStack_Acquire(const RtaCommandDestroyProtocolStack *destroyStack);
+
+/**
+ * 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] closePtr A pointer to the object to release, will return NULL'd.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(stackId);
+ * RtaCommand *command = rtaCommand_CreateDestroyProtocolStack(destroyStack);
+ * _rtaTransport_SendCommandToFramework(transport, command);
+ * rtaCommand_Release(&command);
+ * rtaCommandDestroyProtocolStack(&destroyStack);
+ * }
+ * @endcode
+ */
+void rtaCommandDestroyProtocolStack_Release(RtaCommandDestroyProtocolStack **destroyStackPtr);
+
+/**
+ * Returns the Stack ID of the destroy stack command
+ *
+ * Returns the Stack ID parameter.
+ *
+ * @param [in] destroyStack An allocated RtaCommandDestroyProtocolStack
+ *
+ * @return integer The value passed to rtaCommandDestroyProtocolStack_Create().
+ *
+ * Example:
+ * @code
+ * {
+ * int stackId = 7;
+ * RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(stackId);
+ * int testValue = rtaCommandDestroyProtocolStack_GetStackId(destroyStack);
+ * assertTrue(testValue == stackId, "Wrong value got %d expected %d", testValue, stackId);
+ * rtaCommandDestroyProtocolStack(&destroyStack);
+ * }
+ * @endcode
+ */
+int rtaCommandDestroyProtocolStack_GetStackId(const RtaCommandDestroyProtocolStack *destroyStack);
+#endif // Libccnx_rta_CommandDestroyProtocolStack_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandOpenConnection.c b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandOpenConnection.c
new file mode 100644
index 00000000..1ec1a945
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandOpenConnection.c
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+/**
+ *
+ * Implements the RtaCommandOpenConnection object which signals to RTA Framework to open a new connection
+ * with the given configuration.
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <ccnx/transport/transport_rta/commands/rta_CommandOpenConnection.h>
+
+struct rta_command_openconnection {
+ int stackId;
+ int apiNotifierFd;
+ int transportNotifierFd;
+ PARCJSON *config;
+};
+
+// ======= Private API
+
+static void
+_rtaCommandOpenConnection_Destroy(RtaCommandOpenConnection **openConnectionPtr)
+{
+ RtaCommandOpenConnection *openConnection = *openConnectionPtr;
+ if (openConnection->config != NULL) {
+ parcJSON_Release(&openConnection->config);
+ }
+}
+
+parcObject_ExtendPARCObject(RtaCommandOpenConnection, _rtaCommandOpenConnection_Destroy,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(rtaCommandOpenConnection, RtaCommandOpenConnection);
+
+parcObject_ImplementRelease(rtaCommandOpenConnection, RtaCommandOpenConnection);
+
+// ======= Public API
+
+RtaCommandOpenConnection *
+rtaCommandOpenConnection_Create(int stackId, int apiNotifierFd, int transportNotifierFd, const PARCJSON *config)
+{
+ RtaCommandOpenConnection *openConnection = parcObject_CreateInstance(RtaCommandOpenConnection);
+ openConnection->stackId = stackId;
+ openConnection->apiNotifierFd = apiNotifierFd;
+ openConnection->transportNotifierFd = transportNotifierFd;
+ openConnection->config = parcJSON_Copy(config);
+ return openConnection;
+}
+
+int
+rtaCommandOpenConnection_GetApiNotifierFd(const RtaCommandOpenConnection *openConnection)
+{
+ assertNotNull(openConnection, "Parameter openConnection must be non-null");
+ return openConnection->apiNotifierFd;
+}
+
+int
+rtaCommandOpenConnection_GetStackId(const RtaCommandOpenConnection *openConnection)
+{
+ assertNotNull(openConnection, "Parameter openConnection must be non-null");
+ return openConnection->stackId;
+}
+
+int
+rtaCommandOpenConnection_GetTransportNotifierFd(const RtaCommandOpenConnection *openConnection)
+{
+ assertNotNull(openConnection, "Parameter openConnection must be non-null");
+ return openConnection->transportNotifierFd;
+}
+
+PARCJSON *
+rtaCommandOpenConnection_GetConfig(const RtaCommandOpenConnection *openConnection)
+{
+ assertNotNull(openConnection, "Parameter openConnection must be non-null");
+ return openConnection->config;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandOpenConnection.h b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandOpenConnection.h
new file mode 100644
index 00000000..031ae04b
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandOpenConnection.h
@@ -0,0 +1,219 @@
+/*
+ * 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_CommandOpenConnection.h
+ * @brief Represents a command to open a connection
+ *
+ * Used to construct an RtaCommand object that is passed to rtaTransport_PassCommand() or _rtaTransport_SendCommandToFramework()
+ * to send a command from the API's thread of execution to the Transport's thread of execution.
+ *
+ */
+#ifndef Libccnx_rta_CommandOpenConnection_h
+#define Libccnx_rta_CommandOpenConnection_h
+
+
+struct rta_command_openconnection;
+typedef struct rta_command_openconnection RtaCommandOpenConnection;
+
+/**
+ * Creates a OpenConnection command object
+ *
+ * Creates a OpenConnection command object used to signal the RTA framework to
+ * open a specified connection. The user passes in the two sides of a socket pair
+ * plus the JSON representation of the connection.
+ *
+ * The RTA transport API connector will use the transportNotifierFd side of the socket pair.
+ *
+ * The caller must know the protocol stack handle stackId to specify which stack to
+ * associate the connection with.
+ *
+ * @param [in] stackId The protocol stack handle to use for the connection.
+ * @param [in] apiNotifierFd A descriptor used to notify the API that there's data to read from the transport.
+ * @param [in] transportNotifierFd A descriptor used to notify the Transport there's data to read from the API.
+ * @param [in] config The stack/connection config.
+ *
+ * @return non-null An allocated object
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * void foo(RTATransport *transport)
+ * {
+ * #define API_SIDE 0
+ * #define TRANSPORT_SIDE 1
+ *
+ * int pair[2];
+ * socketpair(AF_LOCAL, SOCK_STREAM, 0, pair);
+ * PARCJSON *config = createConnectionConfig();
+ *
+ * RtaCommandOpenConnection *openCommand = rtaCommandOpenConnection_Create(6, pair[API_SIDE], pair[TRANSPORT_SIDE], config);
+ * RtaCommand *command = rtaCommand_CreateOpenConnection(openCommand);
+ * _rtaTransport_SendCommandToFramework(transport, command);
+ * rtaCommand_Release(&command);
+ * rtaCommandOpenConnection_Release(&openCommand);
+ *
+ * // ... do work ...
+ * RtaCommandCloseConnection *closeCommand = rtaCommandCloseConnection_Create(pair[API_SIDE]);
+ * RtaCommand *command = rtaCommand_CreateCloseConnection(openCommand);
+ * _rtaTransport_SendCommandToFramework(transport, command);
+ * rtaCommand_Release(&command);
+ * rtaCommandCloseConnection_Release(&closeCommand);
+ * }
+ * @endcode
+ */
+RtaCommandOpenConnection *rtaCommandOpenConnection_Create(int stackId, int apiNotifierFd, int transportNotifierFd, const PARCJSON *config);
+
+/**
+ * Increase the number of references to a `RtaCommandOpenConnection`.
+ *
+ * Note that new `RtaCommandOpenConnection` is not created,
+ * only that the given `RtaCommandOpenConnection` reference count is incremented.
+ * Discard the reference by invoking `rtaCommandOpenConnection_Release`.
+ *
+ * @param [in] openConnection The RtaCommandDestroyProtocolStack to reference.
+ *
+ * @return non-null A reference to `openConnection`.
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(6, pair[API_SIDE], pair[TRANSPORT_SIDE], config);
+ * RtaCommandOpenConnection *second = rtaCommandOpenConnection_Acquire(openConnection);
+ *
+ * // release order does not matter
+ * rtaCommandOpenConnection_Release(&openConnection);
+ * rtaCommandOpenConnection_Release(&second);
+ * }
+ * @endcode
+ */
+RtaCommandOpenConnection *rtaCommandOpenConnection_Acquire(const RtaCommandOpenConnection *openConnection);
+
+/**
+ * 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] closePtr A pointer to the object to release, will return NULL'd.
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandOpenConnection *openCommand = rtaCommandOpenConnection_Create(6, pair[API_SIDE], pair[TRANSPORT_SIDE], config);
+ * RtaCommand *command = rtaCommand_CreateOpenConnection(openCommand);
+ * _rtaTransport_SendCommandToFramework(transport, command);
+ * rtaCommand_Release(&command);
+ * rtaCommandOpenConnection_Release(&openCommand);
+ * }
+ * @endcode
+ */
+void rtaCommandOpenConnection_Release(RtaCommandOpenConnection **openPtr);
+
+/**
+ * Returns the Stack ID of the open command
+ *
+ * Returns the Stack ID parameter.
+ *
+ * @param [in] openConnection An allocated RtaCommandOpenConnection
+ *
+ * @return integer The value passed to rtaCommandOpenConnection_Create().
+ *
+ * Example:
+ * @code
+ * {
+ * int stackId = 7;
+ * RtaCommandOpenConnection *openCommand = rtaCommandOpenConnection_Create(apiSocket, pair[API_SIDE], pair[TRANSPORT_SIDE], config);
+ * int testValue = rtaCommandOpenConnection_GetStackId(openCommand);
+ * assertTrue(testValue == stackId, "Wrong value got %d expected %d", testValue, stackId);
+ * rtaCommandOpenConnection_Release(&openCommand);
+ * }
+ * @endcode
+ */
+int rtaCommandOpenConnection_GetStackId(const RtaCommandOpenConnection *openConnection);
+
+/**
+ * Returns the API descriptor of the open command
+ *
+ * Returns the apiNotifierFd parameter. The API descriptor is the side read/written by the API.
+ *
+ * @param [in] openConnection An allocated RtaCommandOpenConnection
+ *
+ * @return integer The value passed to rtaCommandOpenConnection_Create().
+ *
+ * Example:
+ * @code
+ * {
+ * int stackId = 7;
+ * RtaCommandOpenConnection *openCommand = rtaCommandOpenConnection_Create(apiSocket, pair[API_SIDE], pair[TRANSPORT_SIDE], config);
+ * int testValue = rtaCommandOpenConnection_GetApiNotifierFd(openCommand);
+ * assertTrue(testValue == pair[API_SIDE], "Wrong value got %d expected %d", testValue, pair[API_SIDE]);
+ * rtaCommandOpenConnection_Release(&openCommand);
+ * }
+ * @endcode
+ */
+int rtaCommandOpenConnection_GetApiNotifierFd(const RtaCommandOpenConnection *openConnection);
+
+/**
+ * Returns the Transport descriptor of the open command
+ *
+ * Returns the transportNotifierFd parameter. The transport descriptor is the side read/written by the Transport.
+ *
+ * @param [in] openConnection An allocated RtaCommandOpenConnection
+ *
+ * @return integer The value passed to rtaCommandOpenConnection_Create().
+ *
+ * Example:
+ * @code
+ * {
+ * int stackId = 7;
+ * RtaCommandOpenConnection *openCommand = rtaCommandOpenConnection_Create(apiSocket, pair[API_SIDE], pair[TRANSPORT_SIDE], config);
+ * int testValue = rtaCommandOpenConnection_GetTransportNotifierFd(openCommand);
+ * assertTrue(testValue == pair[TRANSPORT_SIDE], "Wrong value got %d expected %d", testValue, pair[TRANSPORT_SIDE]);
+ * rtaCommandOpenConnection_Release(&openCommand);
+ * }
+ * @endcode
+ */
+int rtaCommandOpenConnection_GetTransportNotifierFd(const RtaCommandOpenConnection *openConnection);
+
+/**
+ * Returns the PARCJSON stack configuration of the create stack command
+ *
+ * Returns the JSON representation of the stack configuration.
+ *
+ * @param [in] createStack An allocated RtaCommandCreateProtocolStack
+ *
+ * @return The value passed to rtaCommandCreateProtocolStack_Create().
+ *
+ * Example:
+ * @code
+ * {
+ * int stackId = 7;
+ * PARCJSON *config = createConnectionConfiguration();
+ * RtaCommandOpenConnection *openCommand = rtaCommandOpenConnection_Create(apiSocket, pair[API_SIDE], pair[TRANSPORT_SIDE], config);
+ * PARCJSON *testValue = rtaCommandOpenConnection_GetConfig(openCommand);
+ * assertTrue(ccnxJson_Equals(config, testValue), "Wrong value");
+ * rtaCommandOpenConnection_Release(&openCommand);
+ * parcJSON_Release(&config);
+ * }
+ * @endcode
+ */
+PARCJSON *rtaCommandOpenConnection_GetConfig(const RtaCommandOpenConnection *openConnection);
+#endif // Libccnx_rta_CommandOpenConnection_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandTransmitStatistics.c b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandTransmitStatistics.c
new file mode 100644
index 00000000..129f68c7
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandTransmitStatistics.c
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+/**
+ *
+ * Implements the RtaCommandTransmitStatistics object which signals to RTA Framework to open a new connection
+ * with the given configuration.
+ */
+
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <sys/param.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <ccnx/transport/transport_rta/commands/rta_CommandTransmitStatistics.h>
+
+struct rta_command_transmitstatistics {
+ struct timeval period;
+ char *filename;
+};
+
+// ======= Private API
+
+static void
+_rtaCommandTransmitStatistics_Destroy(RtaCommandTransmitStatistics **transmitStatsPtr)
+{
+ RtaCommandTransmitStatistics *transmitStats = *transmitStatsPtr;
+ parcMemory_Deallocate((void **) &(transmitStats->filename));
+}
+
+parcObject_ExtendPARCObject(RtaCommandTransmitStatistics, _rtaCommandTransmitStatistics_Destroy,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(rtaCommandTransmitStatistics, RtaCommandTransmitStatistics);
+
+parcObject_ImplementRelease(rtaCommandTransmitStatistics, RtaCommandTransmitStatistics);
+
+// ======= Public API
+
+RtaCommandTransmitStatistics *
+rtaCommandTransmitStatistics_Create(struct timeval period, const char *filename)
+{
+ assertNotNull(filename, "Filename must be non-null");
+
+ RtaCommandTransmitStatistics *transmitStats = parcObject_CreateInstance(RtaCommandTransmitStatistics);
+ memcpy(&transmitStats->period, &period, sizeof(struct timeval));
+ transmitStats->filename = parcMemory_StringDuplicate(filename, PATH_MAX);
+
+ return transmitStats;
+}
+
+struct timeval
+rtaCommandTransmitStatistics_GetPeriod(const RtaCommandTransmitStatistics *transmitStats)
+{
+ assertNotNull(transmitStats, "Parameter transmitStats must be non-null");
+ return transmitStats->period;
+}
+
+const char *
+rtaCommandTransmitStatistics_GetFilename(const RtaCommandTransmitStatistics *transmitStats)
+{
+ assertNotNull(transmitStats, "Parameter transmitStats must be non-null");
+ return transmitStats->filename;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandTransmitStatistics.h b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandTransmitStatistics.h
new file mode 100644
index 00000000..cc5c9d02
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/rta_CommandTransmitStatistics.h
@@ -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.
+ */
+
+/**
+ * @file rta_CommandTransmitStatistics.h
+ * @brief Represents a command to setup a statistics file
+ *
+ * Used to construct an RtaCommand object that is passed to rtaTransport_PassCommand() or _rtaTransport_SendCommandToFramework()
+ * to send a command from the API's thread of execution to the Transport's thread of execution.
+ *
+ */
+#ifndef Libccnx_rta_CommandTransmitStatistics_h
+#define Libccnx_rta_CommandTransmitStatistics_h
+
+struct rta_command_transmitstatistics;
+typedef struct rta_command_transmitstatistics RtaCommandTransmitStatistics;
+
+RtaCommandTransmitStatistics *rtaCommandTransmitStatistics_Create(struct timeval period, const char *filename);
+
+/**
+ * Increase the number of references to a `RtaCommandTransmitStatistics`.
+ *
+ * Note that new `RtaCommandTransmitStatistics` is not created,
+ * only that the given `RtaCommandTransmitStatistics` reference count is incremented.
+ * Discard the reference by invoking `rtaCommandTransmitStatistics_Release`.
+ *
+ * @param [in] transmitStats The RtaCommandTransmitStatistics to reference.
+ *
+ * @return non-null A reference to `transmitStats`.
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * RtaCommandOpenConnection *transmitStats = rtaCommandTransmitStatistics_Create((struct timeval) { 1, 2 }, "filename");
+ * RtaCommandOpenConnection *second = rtaCommandTransmitStatistics_Acquire(transmitStats);
+ *
+ * // release order does not matter
+ * rtaCommandTransmitStatistics_Release(&transmitStats);
+ * rtaCommandTransmitStatistics_Release(&second);
+ * }
+ * @endcode
+ */
+RtaCommandTransmitStatistics *rtaCommandTransmitStatistics_Acquire(const RtaCommandTransmitStatistics *transmitStats);
+
+/**
+ * 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] openPtr A pointer to the object to release, will return NULL'd.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+void rtaCommandTransmitStatistics_Release(RtaCommandTransmitStatistics **openPtr);
+
+/**
+ * Returns the time period to use when writing statistics
+ *
+ * The time period is how often the transport will write the statistics to the specified file.
+ *
+ * @param [in] transmitStats An allocated RtaCommandTransmitStatistics
+ *
+ * @return timeval The value passed to rtaCommandTransmitStatistics_Create().
+ *
+ * Example:
+ * @code
+ * {
+ * int stackId = 7;
+ * struct timeval period = { 1, 2 };
+ * const char *filename = "filename";
+ * RtaCommandOpenConnection *transmitStats = rtaCommandTransmitStatistics_Create(period, filename);
+ * struct timeval testValue = rtaCommandTransmitStatistics_GetPeriod(transmitStats);
+ * assertTrue(timercmp(&testValue, &period, ==), "Wrong period");
+ * rtaCommandTransmitStatistics_Release(&transmitStats);
+ * }
+ * @endcode
+ */
+struct timeval rtaCommandTransmitStatistics_GetPeriod(const RtaCommandTransmitStatistics *transmitStats);
+
+/**
+ * Returns the filename to use when writing statistics
+ *
+ * The filename to append statistics to.
+ *
+ * @param [in] transmitStats An allocated RtaCommandTransmitStatistics
+ *
+ * @return timeval The value passed to rtaCommandTransmitStatistics_Create().
+ *
+ * Example:
+ * @code
+ * {
+ * int stackId = 7;
+ * struct timeval period = { 1, 2 };
+ * const char *filename = "filename";
+ * RtaCommandOpenConnection *transmitStats = rtaCommandTransmitStatistics_Create(period, filename);
+ * struct timeval testValue = rtaCommandTransmitStatistics_GetPeriod(transmitStats);
+ * assertTrue(strcmp(filename, testValue) == 0, "Wrong filename");
+ * rtaCommandTransmitStatistics_Release(&transmitStats);
+ * }
+ * @endcode
+ */
+const char *rtaCommandTransmitStatistics_GetFilename(const RtaCommandTransmitStatistics *transmitStats);
+#endif // Libccnx_rta_CommandTransmitStatistics_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/.gitignore b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/.gitignore
new file mode 100644
index 00000000..73fd1137
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/.gitignore
@@ -0,0 +1,7 @@
+test_rta_Command
+test_rta_CommandCloseConnection
+test_rta_CommandCreateProtocolStack
+test_rta_CommandDestroyProtocolStack
+test_rta_CommandOpenConnection
+test_rta_CommandTransmitStatistics
+
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/CMakeLists.txt b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/CMakeLists.txt
new file mode 100644
index 00000000..d3a5f009
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_rta_Command
+ test_rta_CommandCreateProtocolStack
+ test_rta_CommandOpenConnection
+ test_rta_CommandCloseConnection
+ test_rta_CommandDestroyProtocolStack
+ test_rta_CommandTransmitStatistics
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_Command.c b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_Command.c
new file mode 100644
index 00000000..c27cb41d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_Command.c
@@ -0,0 +1,475 @@
+/*
+ * 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 "../rta_Command.c"
+
+#include <inttypes.h>
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(rta_Command)
+{
+ // 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(rta_Command)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_Command)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Release);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_CreateShutdownFramework);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_CreateCloseConnection);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_CreateCreateProtocolStack);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_CreateDestroyProtocolStack);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_CreateOpenConnection);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_CreateTransmitStatistics);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetCloseConnection);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetCreateProtocolStack);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetDestroyProtocolStack);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetOpenConnection);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetTransmitStatistics);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_IsCloseConnection_True);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_IsCreateProtocolStack_True);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_IsDestroyProtocolStack_True);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_IsOpenConnection_True);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_IsShutdownFramework_True);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_IsTransmitStatistics_True);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_IsCloseConnection_False);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_IsCreateProtocolStack_False);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_IsDestroyProtocolStack_False);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_IsOpenConnection_False);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_IsShutdownFramework_False);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_IsTransmitStatistics_False);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Read_Single);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Write_Single);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Read_Underflow);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Write_Overflow);
+
+ // miscellaneous functions
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_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, rtaCommand_Acquire)
+{
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ size_t firstRefCount = parcObject_GetReferenceCount(command);
+
+ RtaCommand *second = rtaCommand_Acquire(command);
+ size_t secondRefCount = parcObject_GetReferenceCount(second);
+
+ assertTrue(secondRefCount == firstRefCount + 1, "Wrong refcount after acquire, got %zu expected %zu", secondRefCount, firstRefCount + 1);
+
+ rtaCommand_Release(&command);
+ rtaCommand_Release(&second);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_Release)
+{
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+
+ RtaCommand *second = rtaCommand_Acquire(command);
+ size_t secondRefCount = parcObject_GetReferenceCount(second);
+
+ rtaCommand_Release(&command);
+ size_t thirdRefCount = parcObject_GetReferenceCount(second);
+
+ assertTrue(thirdRefCount == secondRefCount - 1, "Wrong refcount after release, got %zu expected %zu", thirdRefCount, secondRefCount - 1);
+
+ rtaCommand_Release(&second);
+}
+
+// =======================
+// Create/From operations
+
+LONGBOW_TEST_CASE(Global, rtaCommand_CreateShutdownFramework)
+{
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ assertNotNull(command, "Got null command from create");
+ assertTrue(command->type == RtaCommandType_ShutdownFramework, "Command is not shutdown framework");
+ rtaCommand_Release(&command);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_CreateCloseConnection)
+{
+ RtaCommandCloseConnection *closeConnection = rtaCommandCloseConnection_Create(77);
+ RtaCommand *command = rtaCommand_CreateCloseConnection(closeConnection);
+ assertNotNull(command, "Got null command from create");
+ assertTrue(command->type == RtaCommandType_CloseConnection, "Command is not CloseConnection");
+ rtaCommand_Release(&command);
+ rtaCommandCloseConnection_Release(&closeConnection);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_CreateCreateProtocolStack)
+{
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(111, config);
+
+ RtaCommand *command = rtaCommand_CreateCreateProtocolStack(createStack);
+ assertNotNull(command, "Got null command from create");
+ assertTrue(command->type == RtaCommandType_CreateProtocolStack, "Command is not CreateProtocolStack");
+
+ rtaCommand_Release(&command);
+ rtaCommandCreateProtocolStack_Release(&createStack);
+ ccnxStackConfig_Release(&config);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_CreateDestroyProtocolStack)
+{
+ RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(77);
+ RtaCommand *command = rtaCommand_CreateDestroyProtocolStack(destroyStack);
+ assertNotNull(command, "Got null command from create");
+ assertTrue(command->type == RtaCommandType_DestroyProtocolStack, "Command is not DestroyProtocolStack");
+ rtaCommand_Release(&command);
+ rtaCommandDestroyProtocolStack_Release(&destroyStack);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_CreateOpenConnection)
+{
+ RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(111, 2341, 2450987, NULL);
+ RtaCommand *command = rtaCommand_CreateOpenConnection(openConnection);
+ assertNotNull(command, "Got null command from create");
+ assertTrue(command->type == RtaCommandType_OpenConnection, "Command is not OpenConnection");
+ rtaCommand_Release(&command);
+ rtaCommandOpenConnection_Release(&openConnection);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_CreateTransmitStatistics)
+{
+ RtaCommandTransmitStatistics *transmitStats = rtaCommandTransmitStatistics_Create((struct timeval) { 1, 2 }, "filename");
+ RtaCommand *command = rtaCommand_CreateTransmitStatistics(transmitStats);
+ assertNotNull(command, "Got null command from create");
+ assertTrue(command->type == RtaCommandType_TransmitStatistics, "Command is not TransmitStatistics");
+ rtaCommand_Release(&command);
+ rtaCommandTransmitStatistics_Release(&transmitStats);
+}
+
+// =======================
+// GET operations
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetCloseConnection)
+{
+ RtaCommandCloseConnection *closeConnection = rtaCommandCloseConnection_Create(77);
+ RtaCommand *command = rtaCommand_CreateCloseConnection(closeConnection);
+
+ const RtaCommandCloseConnection *test = rtaCommand_GetCloseConnection(command);
+ assertTrue(test == closeConnection, "Wrong pointers, got %p expected %p", (void *) test, (void *) closeConnection);
+
+ rtaCommand_Release(&command);
+ rtaCommandCloseConnection_Release(&closeConnection);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetCreateProtocolStack)
+{
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(111, config);
+ RtaCommand *command = rtaCommand_CreateCreateProtocolStack(createStack);
+
+ const RtaCommandCreateProtocolStack *test = rtaCommand_GetCreateProtocolStack(command);
+ assertTrue(test == createStack, "Wrong pointers, got %p expected %p", (void *) test, (void *) createStack);
+
+ rtaCommand_Release(&command);
+ rtaCommandCreateProtocolStack_Release(&createStack);
+ ccnxStackConfig_Release(&config);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetDestroyProtocolStack)
+{
+ RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(77);
+ RtaCommand *command = rtaCommand_CreateDestroyProtocolStack(destroyStack);
+
+ const RtaCommandDestroyProtocolStack *test = rtaCommand_GetDestroyProtocolStack(command);
+ assertTrue(test == destroyStack, "Wrong pointers, got %p expected %p", (void *) test, (void *) destroyStack);
+
+ rtaCommand_Release(&command);
+ rtaCommandDestroyProtocolStack_Release(&destroyStack);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetOpenConnection)
+{
+ RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(111, 2341, 2450987, NULL);
+ RtaCommand *command = rtaCommand_CreateOpenConnection(openConnection);
+
+ const RtaCommandOpenConnection *test = rtaCommand_GetOpenConnection(command);
+ assertTrue(test == openConnection, "Wrong pointers, got %p expected %p", (void *) test, (void *) openConnection);
+
+ rtaCommand_Release(&command);
+ rtaCommandOpenConnection_Release(&openConnection);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetTransmitStatistics)
+{
+ RtaCommandTransmitStatistics *transmitStats = rtaCommandTransmitStatistics_Create((struct timeval) { 1, 2 }, "filename");
+ RtaCommand *command = rtaCommand_CreateTransmitStatistics(transmitStats);
+
+ const RtaCommandTransmitStatistics *test = rtaCommand_GetTransmitStatistics(command);
+ assertTrue(test == transmitStats, "Wrong pointers, got %p expected %p", (void *) test, (void *) transmitStats);
+
+ rtaCommand_Release(&command);
+ rtaCommandTransmitStatistics_Release(&transmitStats);
+}
+
+// =======================
+// IsX operations
+
+LONGBOW_TEST_CASE(Global, rtaCommand_IsCloseConnection_True)
+{
+ RtaCommandCloseConnection *closeConnection = rtaCommandCloseConnection_Create(77);
+ RtaCommand *command = rtaCommand_CreateCloseConnection(closeConnection);
+ assertTrue(rtaCommand_IsCloseConnection(command), "Command is not CloseConnection");
+ rtaCommand_Release(&command);
+ rtaCommandCloseConnection_Release(&closeConnection);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_IsCreateProtocolStack_True)
+{
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(111, config);
+ RtaCommand *command = rtaCommand_CreateCreateProtocolStack(createStack);
+ assertTrue(rtaCommand_IsCreateProtocolStack(command), "Command is not CreateProtocolStack");
+ rtaCommand_Release(&command);
+ rtaCommandCreateProtocolStack_Release(&createStack);
+ ccnxStackConfig_Release(&config);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_IsDestroyProtocolStack_True)
+{
+ RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(77);
+ RtaCommand *command = rtaCommand_CreateDestroyProtocolStack(destroyStack);
+ assertTrue(rtaCommand_IsDestroyProtocolStack(command), "Command is not DestroyProtocolStack");
+ rtaCommand_Release(&command);
+ rtaCommandDestroyProtocolStack_Release(&destroyStack);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_IsOpenConnection_True)
+{
+ RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(111, 2341, 2450987, NULL);
+ RtaCommand *command = rtaCommand_CreateOpenConnection(openConnection);
+ assertTrue(rtaCommand_IsOpenConnection(command), "Command is not OpenConnection");
+ rtaCommand_Release(&command);
+ rtaCommandOpenConnection_Release(&openConnection);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_IsShutdownFramework_True)
+{
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ assertTrue(rtaCommand_IsShutdownFramework(command), "Command is not shutdown framework");
+ rtaCommand_Release(&command);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_IsTransmitStatistics_True)
+{
+ RtaCommandTransmitStatistics *transmitStats = rtaCommandTransmitStatistics_Create((struct timeval) { 1, 2 }, "filename");
+ RtaCommand *command = rtaCommand_CreateTransmitStatistics(transmitStats);
+ assertTrue(rtaCommand_IsTransmitStatistics(command), "Command is not TransmitStatistics");
+ rtaCommand_Release(&command);
+ rtaCommandTransmitStatistics_Release(&transmitStats);
+}
+
+
+LONGBOW_TEST_CASE(Global, rtaCommand_IsCloseConnection_False)
+{
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ assertFalse(rtaCommand_IsCloseConnection(command), "Command is not CloseConnection, should be false");
+ rtaCommand_Release(&command);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_IsCreateProtocolStack_False)
+{
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ assertFalse(rtaCommand_IsCreateProtocolStack(command), "Command is not CreateProtocolStack, should be false");
+ rtaCommand_Release(&command);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_IsDestroyProtocolStack_False)
+{
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ assertFalse(rtaCommand_IsDestroyProtocolStack(command), "Command is not DestroyProtocolStack, should be false");
+ rtaCommand_Release(&command);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_IsOpenConnection_False)
+{
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ assertFalse(rtaCommand_IsOpenConnection(command), "Command is not OpenConnection, should be false");
+ rtaCommand_Release(&command);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_IsShutdownFramework_False)
+{
+ RtaCommandCloseConnection *closeConnection = rtaCommandCloseConnection_Create(77);
+ RtaCommand *command = rtaCommand_CreateCloseConnection(closeConnection);
+ assertFalse(rtaCommand_IsShutdownFramework(command), "Command is not ShutdownFramework, should be false");
+ rtaCommand_Release(&command);
+ rtaCommandCloseConnection_Release(&closeConnection);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_IsTransmitStatistics_False)
+{
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ assertFalse(rtaCommand_IsTransmitStatistics(command), "Command is not TransmitStatistics, should be false");
+ rtaCommand_Release(&command);
+}
+
+// ===========================
+// IO operations
+
+/*
+ * Read a single command from a ring buffer
+ */
+LONGBOW_TEST_CASE(Global, rtaCommand_Read_Single)
+{
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(4, NULL);
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+
+ bool success = parcRingBuffer1x1_Put(ring, command);
+ assertTrue(success, "Failed to put command in to ring buffer");
+
+ RtaCommand *test = rtaCommand_Read(ring);
+ assertTrue(test == command, "Wrong pointers, got %p expected %p", (void *) test, (void *) command);
+
+ rtaCommand_Release(&command);
+ parcRingBuffer1x1_Release(&ring);
+}
+
+/*
+ * Write a single command to a ring buffer and make sure it works
+ */
+LONGBOW_TEST_CASE(Global, rtaCommand_Write_Single)
+{
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(4, NULL);
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+
+ bool success = rtaCommand_Write(command, ring);
+ assertTrue(success, "Failed to put command in to ring buffer");
+
+ // We should now have two references
+ assertTrue(parcObject_GetReferenceCount(command) == 2, "Wrong refernce count, got %" PRIu64 " expected %u", parcObject_GetReferenceCount(command), 2);
+
+ RtaCommand *test = rtaCommand_Read(ring);
+ assertTrue(test == command, "Wrong pointers, got %p expected %p", (void *) test, (void *) command);
+
+ rtaCommand_Release(&command);
+ rtaCommand_Release(&test);
+ parcRingBuffer1x1_Release(&ring);
+}
+
+/*
+ * Read from an empty ring buffer
+ */
+LONGBOW_TEST_CASE(Global, rtaCommand_Read_Underflow)
+{
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(4, NULL);
+
+ RtaCommand *test = rtaCommand_Read(ring);
+ assertNull(test, "Should have gotten NULL read from an empty ring buffer");
+
+ parcRingBuffer1x1_Release(&ring);
+}
+
+/*
+ * Write beyond the capacity of the ring buffer
+ */
+LONGBOW_TEST_CASE(Global, rtaCommand_Write_Overflow)
+{
+ // The ring will store up to (ringSize-1) elements, so we can only
+ // have 3 items in a ring of size 4
+ unsigned ringSize = 4;
+ RtaCommand *commandArray[ringSize];
+
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(ringSize, NULL);
+
+ for (int i = 0; i < ringSize; i++) {
+ commandArray[i] = rtaCommand_CreateShutdownFramework();
+ }
+
+ for (int i = 0; i < ringSize - 1; i++) {
+ bool success = rtaCommand_Write(commandArray[i], ring);
+ assertTrue(success, "Failed to put command in to ring buffer");
+ }
+
+ // now put the one that will not fit
+ bool shouldFail = rtaCommand_Write(commandArray[ringSize - 1], ring);
+ assertFalse(shouldFail, "Writing overflow item should have failed");
+
+ // now make sure we read off all the right items
+ for (int i = 0; i < ringSize - 1; i++) {
+ RtaCommand *test = rtaCommand_Read(ring);
+ assertTrue(test == commandArray[i], "Wrong pointers, got %p expected %p", (void *) test, (void *) commandArray[i]);
+ rtaCommand_Release(&test);
+ }
+
+ for (int i = 0; i < ringSize; i++) {
+ rtaCommand_Release(&commandArray[i]);
+ }
+ parcRingBuffer1x1_Release(&ring);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_Display)
+{
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ rtaCommand_Display(command, 3);
+ rtaCommand_Release(&command);
+}
+
+// ===================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_Command);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandCloseConnection.c b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandCloseConnection.c
new file mode 100644
index 00000000..f6c0a3a3
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandCloseConnection.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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../rta_CommandCloseConnection.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(rta_CommandCloseConnection)
+{
+ // 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(rta_CommandCloseConnection)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_CommandCloseConnection)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCloseConnection_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCloseConnection_Create);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCloseConnection_GetApiNotifierFd);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCloseConnection_Release);
+}
+
+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, rtaCommandCloseConnection_Acquire)
+{
+ int apiNotifierFd = 7;
+ RtaCommandCloseConnection *closeConnection = rtaCommandCloseConnection_Create(apiNotifierFd);
+ size_t firstRefCount = parcObject_GetReferenceCount(closeConnection);
+
+ RtaCommandCloseConnection *second = rtaCommandCloseConnection_Acquire(closeConnection);
+ size_t secondRefCount = parcObject_GetReferenceCount(second);
+
+ assertTrue(secondRefCount == firstRefCount + 1, "Wrong refcount after acquire, got %zu expected %zu", secondRefCount, firstRefCount + 1);
+
+ rtaCommandCloseConnection_Release(&closeConnection);
+ rtaCommandCloseConnection_Release(&second);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandCloseConnection_Create)
+{
+ int apiNotifierFd = 7;
+ RtaCommandCloseConnection *closeConnection = rtaCommandCloseConnection_Create(apiNotifierFd);
+ assertNotNull(closeConnection, "Got null from create");
+ assertTrue(closeConnection->apiNotifierFd == apiNotifierFd, "Internal apiSocket wrong, got %d expected %d", closeConnection->apiNotifierFd, apiNotifierFd);
+ rtaCommandCloseConnection_Release(&closeConnection);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandCloseConnection_GetApiNotifierFd)
+{
+ int apiNotifierFd = 7;
+ RtaCommandCloseConnection *closeConnection = rtaCommandCloseConnection_Create(apiNotifierFd);
+
+ int testFd = rtaCommandCloseConnection_GetApiNotifierFd(closeConnection);
+ assertTrue(testFd == apiNotifierFd, "Wrong value, got %d expected %d", testFd, apiNotifierFd);
+
+ rtaCommandCloseConnection_Release(&closeConnection);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandCloseConnection_Release)
+{
+ int apiNotifierFd = 7;
+ RtaCommandCloseConnection *closeConnection = rtaCommandCloseConnection_Create(apiNotifierFd);
+
+ RtaCommandCloseConnection *second = rtaCommandCloseConnection_Acquire(closeConnection);
+ size_t secondRefCount = parcObject_GetReferenceCount(second);
+
+ rtaCommandCloseConnection_Release(&closeConnection);
+ size_t thirdRefCount = parcObject_GetReferenceCount(second);
+
+ assertTrue(thirdRefCount == secondRefCount - 1, "Wrong refcount after release, got %zu expected %zu", thirdRefCount, secondRefCount - 1);
+
+ rtaCommandCloseConnection_Release(&second);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_CommandCloseConnection);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandCreateProtocolStack.c b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandCreateProtocolStack.c
new file mode 100644
index 00000000..948477f8
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandCreateProtocolStack.c
@@ -0,0 +1,215 @@
+/*
+ * 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 "../rta_CommandCreateProtocolStack.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(rta_CommandCreateProtocolStack)
+{
+ // 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(rta_CommandCreateProtocolStack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_CommandCreateProtocolStack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCreateProtocolStack_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCreateProtocolStack_Create);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCreateProtocolStack_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCreateProtocolStack_IsValid_NULL);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCreateProtocolStack_IsValid_BadCCNxStackConfig);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCreateProtocolStack_AssertValid);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCreateProtocolStack_GetConfig);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCreateProtocolStack_GetStackId);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCreateProtocolStack_GetStackConfig);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandCreateProtocolStack_Release);
+}
+
+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, rtaCommandCreateProtocolStack_Acquire)
+{
+ int stackId = 7;
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+
+ parcObjectTesting_AssertAcquire(createStack);
+
+ rtaCommandCreateProtocolStack_Release(&createStack);
+ ccnxStackConfig_Release(&config);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandCreateProtocolStack_Create)
+{
+ int stackId = 7;
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+ assertNotNull(createStack, "Expected rtaCommandCreateProtocolStack_Create to return non-NULL.");
+
+ assertTrue(createStack->stackId == stackId, "Expected stackId %d, actual %d", stackId, createStack->stackId);
+
+ assertTrue(ccnxStackConfig_Equals(config, createStack->config),
+ "ProtocolStackConfig instances are not equal");
+ rtaCommandCreateProtocolStack_Release(&createStack);
+ ccnxStackConfig_Release(&config);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandCreateProtocolStack_IsValid)
+{
+ int stackId = 7;
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+
+ assertTrue(rtaCommandCreateProtocolStack_IsValid(createStack),
+ "Expected rtaCommandCreateProtocolStack_Create to return a valid instance.");
+
+ rtaCommandCreateProtocolStack_Release(&createStack);
+ ccnxStackConfig_Release(&config);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandCreateProtocolStack_IsValid_NULL)
+{
+ RtaCommandCreateProtocolStack *createStack = NULL;
+
+ assertFalse(rtaCommandCreateProtocolStack_IsValid(createStack),
+ "Expected rtaCommandCreateProtocolStack_Create to return a valid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandCreateProtocolStack_IsValid_BadCCNxStackConfig)
+{
+ int stackId = 7;
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+ CCNxStackConfig *original = createStack->config;
+ createStack->config = NULL; // Make it bad.
+ assertFalse(rtaCommandCreateProtocolStack_IsValid(createStack),
+ "Expected rtaCommandCreateProtocolStack_Create to return a valid instance.");
+ createStack->config = original;
+ rtaCommandCreateProtocolStack_Release(&createStack);
+ ccnxStackConfig_Release(&config);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandCreateProtocolStack_AssertValid)
+{
+ int stackId = 7;
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+
+ rtaCommandCreateProtocolStack_AssertValid(createStack);
+
+ rtaCommandCreateProtocolStack_Release(&createStack);
+ ccnxStackConfig_Release(&config);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandCreateProtocolStack_GetStackConfig)
+{
+ int stackId = 7;
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+
+ CCNxStackConfig *actual = rtaCommandCreateProtocolStack_GetStackConfig(createStack);
+
+ assertTrue(ccnxStackConfig_Equals(config, actual),
+ "CCNxStackConfig instances are not equal");
+
+ rtaCommandCreateProtocolStack_Release(&createStack);
+ ccnxStackConfig_Release(&config);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandCreateProtocolStack_GetConfig)
+{
+ int stackId = 7;
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+
+ assertTrue(ccnxStackConfig_Equals(config, createStack->config),
+ "ProtocolStackConfig instances are not equal");
+
+ rtaCommandCreateProtocolStack_Release(&createStack);
+ ccnxStackConfig_Release(&config);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandCreateProtocolStack_GetStackId)
+{
+ int stackId = 7;
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+
+ int testStackId = rtaCommandCreateProtocolStack_GetStackId(createStack);
+ assertTrue(testStackId == stackId, "Wrong value, got %d expected %d", testStackId, stackId);
+
+ rtaCommandCreateProtocolStack_Release(&createStack);
+ ccnxStackConfig_Release(&config);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandCreateProtocolStack_Release)
+{
+ int stackId = 7;
+ CCNxStackConfig *config = ccnxStackConfig_Create();
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, config);
+
+ RtaCommandCreateProtocolStack *second = rtaCommandCreateProtocolStack_Acquire(createStack);
+ size_t secondRefCount = parcObject_GetReferenceCount(second);
+
+ rtaCommandCreateProtocolStack_Release(&createStack);
+ size_t thirdRefCount = parcObject_GetReferenceCount(second);
+
+ assertTrue(thirdRefCount == secondRefCount - 1,
+ "Wrong refcount after release, got %zu expected %zu", thirdRefCount, secondRefCount - 1);
+
+ rtaCommandCreateProtocolStack_Release(&second);
+ ccnxStackConfig_Release(&config);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_CommandCreateProtocolStack);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandDestroyProtocolStack.c b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandDestroyProtocolStack.c
new file mode 100644
index 00000000..37e1128d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandDestroyProtocolStack.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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../rta_CommandDestroyProtocolStack.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(rta_CommandDestroyProtocolStack)
+{
+ // 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(rta_CommandDestroyProtocolStack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_CommandDestroyProtocolStack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandDestroyProtocolStack_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandDestroyProtocolStack_Create);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandDestroyProtocolStack_GetStackId);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandDestroyProtocolStack_Release);
+}
+
+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, rtaCommandDestroyProtocolStack_Acquire)
+{
+ int stackId = 7;
+ RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(stackId);
+ size_t firstRefCount = parcObject_GetReferenceCount(destroyStack);
+
+ RtaCommandDestroyProtocolStack *second = rtaCommandDestroyProtocolStack_Acquire(destroyStack);
+ size_t secondRefCount = parcObject_GetReferenceCount(second);
+
+ assertTrue(secondRefCount == firstRefCount + 1, "Wrong refcount after acquire, got %zu expected %zu", secondRefCount, firstRefCount + 1);
+
+ rtaCommandDestroyProtocolStack_Release(&destroyStack);
+ rtaCommandDestroyProtocolStack_Release(&second);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandDestroyProtocolStack_Create)
+{
+ int stackId = 7;
+ RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(stackId);
+ assertNotNull(destroyStack, "Got null from create");
+ assertTrue(destroyStack->stackId == stackId, "Internal stackId wrong, got %d expected %d", destroyStack->stackId, stackId);
+ rtaCommandDestroyProtocolStack_Release(&destroyStack);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandDestroyProtocolStack_GetStackId)
+{
+ int stackId = 7;
+ RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(stackId);
+
+ int testStackId = rtaCommandDestroyProtocolStack_GetStackId(destroyStack);
+ assertTrue(testStackId == stackId, "Wrong value, got %d expected %d", testStackId, stackId);
+
+ rtaCommandDestroyProtocolStack_Release(&destroyStack);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandDestroyProtocolStack_Release)
+{
+ int stackId = 7;
+ RtaCommandDestroyProtocolStack *destroyStack = rtaCommandDestroyProtocolStack_Create(stackId);
+
+ RtaCommandDestroyProtocolStack *second = rtaCommandDestroyProtocolStack_Acquire(destroyStack);
+ size_t secondRefCount = parcObject_GetReferenceCount(second);
+
+ rtaCommandDestroyProtocolStack_Release(&destroyStack);
+ size_t thirdRefCount = parcObject_GetReferenceCount(second);
+
+ assertTrue(thirdRefCount == secondRefCount - 1, "Wrong refcount after release, got %zu expected %zu", thirdRefCount, secondRefCount - 1);
+
+ rtaCommandDestroyProtocolStack_Release(&second);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_CommandDestroyProtocolStack);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandOpenConnection.c b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandOpenConnection.c
new file mode 100644
index 00000000..30d77931
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandOpenConnection.c
@@ -0,0 +1,199 @@
+/*
+ * 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 "../rta_CommandOpenConnection.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+typedef struct test_data {
+ int stackId;
+ int apiNotifierFd;
+ int transportNotifierFd;
+ PARCJSON *config;
+
+ RtaCommandOpenConnection *openConnection;
+} TestData;
+
+static TestData *
+_createTestData(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+
+ data->stackId = 7;
+ data->apiNotifierFd = 11;
+ data->transportNotifierFd = 10029;
+ data->config = parcJSON_Create();
+
+ data->openConnection = rtaCommandOpenConnection_Create(data->stackId, data->apiNotifierFd, data->transportNotifierFd, data->config);
+
+ return data;
+}
+
+static void
+_destroyTestData(TestData **dataPtr)
+{
+ TestData *data = *dataPtr;
+
+ rtaCommandOpenConnection_Release(&data->openConnection);
+ parcJSON_Release(&data->config);
+ parcMemory_Deallocate((void **) &data);
+
+ *dataPtr = NULL;
+}
+
+// =============================================================
+
+LONGBOW_TEST_RUNNER(rta_CommandOpenConnection)
+{
+ // 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(rta_CommandOpenConnection)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_CommandOpenConnection)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandOpenConnection_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandOpenConnection_Create);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandOpenConnection_GetApiNotifierFd);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandOpenConnection_GetConfig);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandOpenConnection_GetStackId);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandOpenConnection_GetTransportNotifierFd);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandOpenConnection_Release);
+}
+
+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, rtaCommandOpenConnection_Acquire)
+{
+ TestData *data = _createTestData();
+
+ size_t firstRefCount = parcObject_GetReferenceCount(data->openConnection);
+
+ RtaCommandOpenConnection *second = rtaCommandOpenConnection_Acquire(data->openConnection);
+ size_t secondRefCount = parcObject_GetReferenceCount(second);
+
+ assertTrue(secondRefCount == firstRefCount + 1, "Wrong refcount after acquire, got %zu expected %zu", secondRefCount, firstRefCount + 1);
+
+ rtaCommandOpenConnection_Release(&second);
+ _destroyTestData(&data);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandOpenConnection_Create)
+{
+ TestData *data = _createTestData();
+ assertNotNull(data->openConnection, "Got null from create");
+ assertTrue(data->openConnection->stackId == data->stackId, "Internal stackId wrong, got %d expected %d",
+ data->openConnection->stackId, data->stackId);
+ assertTrue(data->openConnection->apiNotifierFd == data->apiNotifierFd, "Internal apiNotifierFd wrong, got %d expected %d",
+ data->openConnection->apiNotifierFd, data->apiNotifierFd);
+ assertTrue(data->openConnection->transportNotifierFd == data->transportNotifierFd, "Internal transportNotifierFd wrong, got %d expected %d",
+ data->openConnection->transportNotifierFd, data->transportNotifierFd);
+ assertTrue(parcJSON_Equals(data->openConnection->config, data->config), "JSON configs are not equal");
+ _destroyTestData(&data);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandOpenConnection_GetApiNotifierFd)
+{
+ TestData *data = _createTestData();
+
+ int testApiFd = rtaCommandOpenConnection_GetApiNotifierFd(data->openConnection);
+ assertTrue(testApiFd == data->apiNotifierFd, "Wrong value, got %d expected %d", testApiFd, data->apiNotifierFd);
+
+ _destroyTestData(&data);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandOpenConnection_GetConfig)
+{
+ TestData *data = _createTestData();
+
+ PARCJSON *testConfig = rtaCommandOpenConnection_GetConfig(data->openConnection);
+ assertTrue(parcJSON_Equals(data->config, testConfig), "Configurations do not match");
+
+ _destroyTestData(&data);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandOpenConnection_GetStackId)
+{
+ TestData *data = _createTestData();
+
+ int testStackId = rtaCommandOpenConnection_GetStackId(data->openConnection);
+ assertTrue(testStackId == data->stackId, "Wrong value, got %d expected %d", testStackId, data->stackId);
+
+ _destroyTestData(&data);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandOpenConnection_GetTransportNotifierFd)
+{
+ TestData *data = _createTestData();
+
+ int testTransportFd = rtaCommandOpenConnection_GetTransportNotifierFd(data->openConnection);
+ assertTrue(testTransportFd == data->transportNotifierFd, "Wrong value, got %d expected %d", testTransportFd, data->transportNotifierFd);
+
+ _destroyTestData(&data);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandOpenConnection_Release)
+{
+ TestData *data = _createTestData();
+
+ RtaCommandOpenConnection *second = rtaCommandOpenConnection_Acquire(data->openConnection);
+ size_t secondRefCount = parcObject_GetReferenceCount(second);
+
+ rtaCommandOpenConnection_Release(&second);
+ size_t thirdRefCount = parcObject_GetReferenceCount(data->openConnection);
+
+ assertTrue(thirdRefCount == secondRefCount - 1, "Wrong refcount after release, got %zu expected %zu", thirdRefCount, secondRefCount - 1);
+
+ _destroyTestData(&data);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_CommandOpenConnection);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandTransmitStatistics.c b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandTransmitStatistics.c
new file mode 100644
index 00000000..cc312e5a
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/commands/test/test_rta_CommandTransmitStatistics.c
@@ -0,0 +1,170 @@
+/*
+ * 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 "../rta_CommandTransmitStatistics.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <sys/time.h>
+
+#define MAX_FILENAME 1024
+
+typedef struct test_data {
+ struct timeval period;
+ char filename[MAX_FILENAME];
+
+ RtaCommandTransmitStatistics *transmitStats;
+} TestData;
+
+static TestData *
+_createTestData(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->period = (struct timeval) { .tv_sec = 1234, .tv_usec = 2389484 };
+ snprintf(data->filename, MAX_FILENAME, "Miss Piggy");
+
+ data->transmitStats = rtaCommandTransmitStatistics_Create(data->period, data->filename);
+
+ return data;
+}
+
+static void
+_destroyTestData(TestData **dataPtr)
+{
+ TestData *data = *dataPtr;
+ rtaCommandTransmitStatistics_Release(&data->transmitStats);
+ parcMemory_Deallocate((void **) &data);
+ *dataPtr = NULL;
+}
+
+// =============================================================
+LONGBOW_TEST_RUNNER(rta_CommandTransmitStatistics)
+{
+ // 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(rta_CommandTransmitStatistics)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_CommandTransmitStatistics)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandTransmitStatistics_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandTransmitStatistics_Create);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandTransmitStatistics_GetFilename);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandTransmitStatistics_GetPeriod);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommandTransmitStatistics_Release);
+}
+
+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, rtaCommandTransmitStatistics_Acquire)
+{
+ TestData *data = _createTestData();
+
+ size_t firstRefCount = parcObject_GetReferenceCount(data->transmitStats);
+
+ RtaCommandTransmitStatistics *second = rtaCommandTransmitStatistics_Acquire(data->transmitStats);
+ size_t secondRefCount = parcObject_GetReferenceCount(second);
+
+ assertTrue(secondRefCount == firstRefCount + 1, "Wrong refcount after acquire, got %zu expected %zu", secondRefCount, firstRefCount + 1);
+
+ rtaCommandTransmitStatistics_Release(&second);
+ _destroyTestData(&data);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandTransmitStatistics_Create)
+{
+ TestData *data = _createTestData();
+ assertNotNull(data->transmitStats, "Got null from create");
+
+ assertTrue(timercmp(&data->period, &data->transmitStats->period, ==), "Period values not equal");
+ assertTrue(strcmp(data->filename, data->transmitStats->filename) == 0, "Filenames not equal");
+ _destroyTestData(&data);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandTransmitStatistics_GetFilename)
+{
+ TestData *data = _createTestData();
+
+ const char *testFilename = rtaCommandTransmitStatistics_GetFilename(data->transmitStats);
+ assertTrue(strcmp(data->filename, testFilename) == 0, "Filenames not equal");
+
+ _destroyTestData(&data);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandTransmitStatistics_GetPeriod)
+{
+ TestData *data = _createTestData();
+
+ struct timeval testPeriod = rtaCommandTransmitStatistics_GetPeriod(data->transmitStats);
+ assertTrue(timercmp(&data->period, &testPeriod, ==), "Period values not equal");
+
+ _destroyTestData(&data);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommandTransmitStatistics_Release)
+{
+ TestData *data = _createTestData();
+
+ RtaCommandTransmitStatistics *second = rtaCommandTransmitStatistics_Acquire(data->transmitStats);
+ size_t secondRefCount = parcObject_GetReferenceCount(second);
+
+ rtaCommandTransmitStatistics_Release(&second);
+ size_t thirdRefCount = parcObject_GetReferenceCount(data->transmitStats);
+
+ assertTrue(thirdRefCount == secondRefCount - 1, "Wrong refcount after release, got %zu expected %zu", thirdRefCount, secondRefCount - 1);
+
+ _destroyTestData(&data);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_CommandTransmitStatistics);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/component_Vegas.c b/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/component_Vegas.c
new file mode 100644
index 00000000..70bcec63
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/component_Vegas.c
@@ -0,0 +1,673 @@
+/*
+ * 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.
+ */
+// Source code layout:
+// - component_Vegas.c: the component wrapper and session multiplexing
+// - vegas_Session.c: code for a specific basename session
+// - vegas_Segment.c: code for specific segment operations
+
+/**
+ * Component behavior
+ * ===================
+ * This component provides flow-controlled in-order delivery of segmented
+ * content objects using a sequential segment number in the last component
+ * of the object name.
+ *
+ * The state machine described here is within a single RtaConnection. Separate
+ * connections are independent.
+ *
+ * Down Stack Behavior
+ * ------------------------
+ * When an interest comes down the stack, it will initiate a flow-controlled
+ * session. If the last component of the interest name is a segment number,
+ * that is the starting segment number. Otherwise, we assume the interest
+ * name is the base name for a segmented object, including the version number.
+ *
+ * Other types of messages coming down the stack (e.g. control or content objects)
+ * are passed down the stack unaltered.
+ *
+ * If an interest comes down that represents a subset of an existing flow (i.e.
+ * it has a segment number beyond the current starting segment of the flow contol
+ * window), the window is advanced to that segment number and any un-delivered
+ * content objects are dropped.
+ *
+ * If an interest comes down that represents a superset of an existing flow
+ * (i.e. it has a starting segment number less than the current window), the
+ * current flow control sessions is re-wound to the lower sequence number
+ * and continues from there.
+ *
+ * Up Stack Behavior
+ * ------------------------
+ * Non-content objects (e.g. control and interests) are passed up the stack unmodified.
+ *
+ * A content object that matches a flow control session is managed by the session.
+ * They are only passed up the stack in-order, and will be dropped if they are outside
+ * the window.
+ *
+ * A content object that does not match a flow control session is dropped. That's because
+ * the only interests we send down the stack are our own for flow controlled sessions, so
+ * no content object should go up the stack unless its part of a flow controlled session.
+ *
+ * Control Messages
+ * ------------------------
+ * The API may cancel flow control sessions in several ways:
+ *
+ * 1) Close the Connection. This will cancel all in progress sessions and drop
+ * any un-delivered objects.
+ *
+ * 2) Send a Control message down the stack with the base name to cancel. The
+ * name is considered the base name of the flow and does not depend on the
+ * starting segment number.
+ *
+ * { "CPI_CANCEL_FLOW" : { "FLOW_NAME" : <base name w/o segment number> } }
+ *
+ * Implementation Notes
+ * =========================
+ * For each RtaConnection, there's a {@code struct fc_connection_state}. This
+ * contains a list of in-progress sessions indexed by the hash of the base name
+ * (name up to but not including final segment). Right now, it's a linked list
+ * but should be implemented as a hash table.
+ *
+ * Each session is represented by a {@code struct fc_session}.
+ *
+ * Each entry in the flow control window is a {@code fc_window_entry}.
+ *
+ * session->window_head and session->window_tail define the limits of the
+ * congestion window. Everything in the interval [head, tail) is expressed
+ * as an interest. The size of that interval may be larger than the
+ * congestion window cwnd if we're decreaed the window. We never decrease
+ * tail, only the cwnd.
+ *
+ *
+ * Flow Control Algorithm
+ * =========================
+ * Based on TCP Vegas. Please read the Vegas paper. We use similar
+ * variable names to the paper. Code looks quite a bit like the linux
+ * tcp_vegas.c too.
+ *
+ * Here's the differences. In CCN, an Interest is like an ACK token, it
+ * gives the network permission to send. The node issuing Interests needs
+ * to pace them to not exceed the network capacity. This is done by
+ * observing the delay of Content Objects. If the delay grows too quickly,
+ * then we back off linearly. If the delay is not much above what we expected
+ * based on the minimum observed delay, we increase linearly.
+ *
+ * During slow start, the interest window (still called "cwnd") doubles
+ * every other RTT until we exceed the slow_start_threshold or the delay
+ * increases too much.
+ *
+ * The RTT is calculated every RTT based on the observed minimum RTT during
+ * the previous period.
+ *
+ * We use RFC6298 Retransmission Timeout (RTO) calculation methods per
+ * flow control session (object basename).
+ *
+ * Just to be clear, there are two timers working. The RTO timer is for
+ * retransmitting interests if the flow as stalled out. The Vegas RTT
+ * calculation is for congestion window calculations.
+ *
+ * We we receive an out-of-order content object, we'll check the earlier
+ * segments to see if they have passed the Vegas RTT. If so, we'll
+ * re-express the interests.
+ *
+ * Each time we re-express an Interest, we might decrese the congestion
+ * window. If the last time the interest was sent was more recent than
+ * the last time we decreased the congestion window, we'll decrease the
+ * congestion window. If the last expression of the interest was before
+ * the most recent window decrease, the window is left alone. This means
+ * we'll only decreae the window once per re-expression.
+ */
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <limits.h>
+#include <sys/queue.h>
+#include <stdbool.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_EventQueue.h>
+
+#include <ccnx/transport/common/transport_Message.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+#include <ccnx/transport/transport_rta/components/component_Flowcontrol.h>
+#include <ccnx/transport/test_tools/traffic_tools.h>
+
+#include <ccnx/api/control/controlPlaneInterface.h>
+#include <ccnx/api/control/cpi_ControlFacade.h>
+
+#include "vegas_private.h"
+
+#include <parc/logging/parc_LogLevel.h>
+
+#ifndef DEBUG_OUTPUT
+#define DEBUG_OUTPUT 0
+#endif
+
+// ===========================================================
+
+typedef struct fc_session_holder {
+ uint64_t basename_hash;
+ CCNxName *basename;
+ VegasSession *session;
+
+ // used by fc_connection_state to hold these
+ // Should change to hashtable on the hash
+ TAILQ_ENTRY(fc_session_holder) list;
+} FcSessionHolder;
+
+/**
+ * This is the per-connection state. It allows us to have multiple
+ * flow control session on one connection for different names
+ */
+struct vegas_connection_state {
+ RtaConnection *parent_connection;
+ RtaFramework *parent_framework;
+
+ TAILQ_HEAD(, fc_session_holder) sessions_head;
+};
+
+
+// ===========================================================
+
+static int component_Fc_Vegas_Init(RtaProtocolStack *stack);
+static int component_Fc_Vegas_Opener(RtaConnection *conn);
+static void component_Fc_Vegas_Upcall_Read(PARCEventQueue *, PARCEventType event, void *conn);
+static void component_Fc_Vegas_Downcall_Read(PARCEventQueue *, PARCEventType event, void *conn);
+static int component_Fc_Vegas_Closer(RtaConnection *conn);
+static int component_Fc_Vegas_Release(RtaProtocolStack *stack);
+static void component_Fc_Vegas_StateChange(RtaConnection *conn);
+
+// Function structs for component variations
+RtaComponentOperations flow_vegas_ops = {
+ .init = component_Fc_Vegas_Init,
+ .open = component_Fc_Vegas_Opener,
+ .upcallRead = component_Fc_Vegas_Upcall_Read,
+ .upcallEvent = NULL,
+ .downcallRead = component_Fc_Vegas_Downcall_Read,
+ .downcallEvent = NULL,
+ .close = component_Fc_Vegas_Closer,
+ .release = component_Fc_Vegas_Release,
+ .stateChange = component_Fc_Vegas_StateChange
+};
+
+
+// ======
+// Session related functions
+static int vegas_HandleInterest(RtaConnection *conn, TransportMessage *tm);
+static FcSessionHolder *vegas_LookupSession(VegasConnectionState *fc, TransportMessage *tm);
+static FcSessionHolder *vegas_LookupSessionByName(VegasConnectionState *fc, CCNxName *name);
+
+static FcSessionHolder *vegas_CreateSessionHolder(VegasConnectionState *fc, RtaConnection *conn,
+ CCNxName *basename, uint64_t name_hash);
+
+static bool vegas_HandleControl(RtaConnection *conn, CCNxTlvDictionary *controlDictionary, PARCEventQueue *outputQueue);
+
+// ================================================
+
+static int
+component_Fc_Vegas_Init(RtaProtocolStack *stack)
+{
+ // we don't do any stack-wide initialization
+ return 0;
+}
+
+static int
+component_Fc_Vegas_Opener(RtaConnection *conn)
+{
+ struct vegas_connection_state *fcConnState = parcMemory_AllocateAndClear(sizeof(struct vegas_connection_state));
+ assertNotNull(fcConnState, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(struct vegas_connection_state));
+
+ fcConnState->parent_connection = rtaConnection_Copy(conn);
+ fcConnState->parent_framework = rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn));
+
+ TAILQ_INIT(&fcConnState->sessions_head);
+
+ rtaConnection_SetPrivateData(conn, FC_VEGAS, fcConnState);
+ rtaComponentStats_Increment(rtaConnection_GetStats(conn, FC_VEGAS), STATS_OPENS);
+
+ return 0;
+}
+
+/*
+ * Read from below.
+ * These should only be content objects associated with our stream.
+ *
+ * Non-content objects are passed up the stack.
+ */
+static void
+component_Fc_Vegas_Upcall_Read(PARCEventQueue *in, PARCEventType event, void *stack_ptr)
+{
+ TransportMessage *tm;
+
+ while ((tm = rtaComponent_GetMessage(in)) != NULL) {
+ struct timeval delay = transportMessage_GetDelay(tm);
+
+ RtaConnection *conn = rtaConnection_GetFromTransport(tm);
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, FC_VEGAS);
+
+ rtaComponentStats_Increment(stats, STATS_UPCALL_IN);
+
+ if (transportMessage_IsControl(tm)) {
+ PARCEventQueue *out = rtaComponent_GetOutputQueue(conn, FC_VEGAS, RTA_UP);
+
+ if (rtaComponent_PutMessage(out, tm)) {
+ rtaComponentStats_Increment(stats, STATS_UPCALL_OUT);
+ } else {
+ //TODO
+ }
+ } else if (transportMessage_IsContentObject(tm)) {
+ // this takes ownership of the transport message
+ VegasConnectionState *fc = rtaConnection_GetPrivateData(conn, FC_VEGAS);
+ FcSessionHolder *holder = vegas_LookupSession(fc, tm);
+
+ // it's quite possible that we get content objects for sessions that
+ // no longer exist. They are dropped.
+ if (holder != NULL) {
+ vegasSession_ReceiveContentObject(holder->session, tm);
+ } else {
+ transportMessage_Destroy(&tm);
+ }
+ } else {
+ PARCEventQueue *out = rtaComponent_GetOutputQueue(conn, FC_VEGAS, RTA_UP);
+ if (rtaComponent_PutMessage(out, tm)) {
+ rtaComponentStats_Increment(stats, STATS_UPCALL_OUT);
+ } else {
+ //TODO
+ }
+ }
+
+ if (DEBUG_OUTPUT) {
+ printf("%s total upcall reads in %" PRIu64 " out %" PRIu64 " last delay %.6f\n",
+ __func__,
+ rtaComponentStats_Get(stats, STATS_UPCALL_IN),
+ rtaComponentStats_Get(stats, STATS_UPCALL_OUT),
+ delay.tv_sec + delay.tv_usec * 1E-6);
+ }
+ }
+}
+
+static void
+component_Fc_Vegas_Downcall_Read(PARCEventQueue *in, PARCEventType event, void *conn)
+{
+ RtaProtocolStack *stack = (RtaProtocolStack *) conn;
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(stack, FC_VEGAS, RTA_DOWN);
+ TransportMessage *tm;
+
+// printf("%s reading from queue %p\n", __func__, in);
+
+ while ((tm = rtaComponent_GetMessage(in)) != NULL) {
+ RtaConnection *conn = rtaConnection_GetFromTransport(tm);
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, FC_VEGAS);
+ rtaComponentStats_Increment(stats, STATS_DOWNCALL_IN);
+
+ if (transportMessage_IsControl(tm)) {
+ CCNxTlvDictionary *controlDictionary = transportMessage_GetDictionary(tm);
+ if (ccnxControlFacade_IsCPI(controlDictionary) && vegas_HandleControl(conn, controlDictionary, in)) {
+ transportMessage_Destroy(&tm);
+ } else {
+ // we did not consume the message, so forward it down
+ if (rtaComponent_PutMessage(out, tm)) {
+ rtaComponentStats_Increment(stats, STATS_DOWNCALL_OUT);
+ }
+ }
+ } else if (transportMessage_IsInterest(tm)) {
+ vegas_HandleInterest(conn, tm);
+
+ // The flow controller consumes Interests going down the stack and will
+ // start issuing its own interests instead.
+ transportMessage_Destroy(&tm);
+ } else {
+ if (rtaComponent_PutMessage(out, tm)) {
+ rtaComponentStats_Increment(stats, STATS_DOWNCALL_OUT);
+ }
+ }
+
+ if (DEBUG_OUTPUT) {
+ struct timeval delay = tm ? transportMessage_GetDelay(tm) : (struct timeval) { 0, 0 };
+ printf("%s total downcall reads in %" PRIu64 " out %" PRIu64 " last delay %.6f\n",
+ __func__,
+ rtaComponentStats_Get(stats, STATS_DOWNCALL_IN),
+ rtaComponentStats_Get(stats, STATS_DOWNCALL_OUT),
+ delay.tv_sec + delay.tv_usec * 1E-6);
+ }
+ }
+}
+
+static int
+component_Fc_Vegas_Closer(RtaConnection *conn)
+{
+ VegasConnectionState *fcConnState;
+
+ assertNotNull(conn, "Got null connection\n");
+ if (conn == NULL) {
+ return -1;
+ }
+
+ fcConnState = rtaConnection_GetPrivateData(conn, FC_VEGAS);
+
+ assertNotNull(fcConnState, "could not retrieve private data for FC_VEGAS on connid %u\n",
+ rtaConnection_GetConnectionId(conn));
+ if (fcConnState == NULL) {
+ return -1;
+ }
+
+ rtaConnection_Destroy(&fcConnState->parent_connection);
+
+ rtaComponentStats_Increment(rtaConnection_GetStats(conn, FC_VEGAS), STATS_CLOSES);
+
+ // close down all the sessions
+ while (!TAILQ_EMPTY(&fcConnState->sessions_head)) {
+ FcSessionHolder *holder = TAILQ_FIRST(&fcConnState->sessions_head);
+
+ vegasSession_Destroy(&holder->session);
+
+ TAILQ_REMOVE(&fcConnState->sessions_head, holder, list);
+ parcMemory_Deallocate((void **) &holder);
+ }
+
+ parcMemory_Deallocate((void **) &fcConnState);
+
+ return 0;
+}
+
+static int
+component_Fc_Vegas_Release(RtaProtocolStack *stack)
+{
+ // no stack-wide memory
+ return 0;
+}
+
+static void
+component_Fc_Vegas_StateChange(RtaConnection *conn)
+{
+ assertNotNull(conn, "Got null connection\n");
+
+ VegasConnectionState *fcConnState = rtaConnection_GetPrivateData(conn, FC_VEGAS);
+ assertNotNull(fcConnState, "could not retrieve private data for FC_VEGAS on connid %u\n",
+ rtaConnection_GetConnectionId(conn));
+
+ // should replace this with a hash table
+ FcSessionHolder *holder;
+ TAILQ_FOREACH(holder, &fcConnState->sessions_head, list)
+ {
+ if (vegasSession_GetConnectionId(holder->session) == rtaConnection_GetConnectionId(conn)) {
+ vegasSession_StateChanged(holder->session);
+ }
+ }
+}
+
+// =======================================================================
+
+/**
+ * If the last component is a segment number, it is ignored
+ */
+static FcSessionHolder *
+vegas_LookupSessionByName(VegasConnectionState *fc, CCNxName *name)
+{
+ uint64_t hash;
+ FcSessionHolder *holder;
+ int trim_segnum = 0;
+
+ assertNotNull(name, "Name is null\n");
+ if (name == NULL) {
+ return NULL;
+ }
+
+ size_t segmentCount = ccnxName_GetSegmentCount(name);
+ assertTrue(segmentCount > 1,
+ "expected name with at least 2 components, but only got %zu, name = '%s'\n",
+ segmentCount,
+ ccnxName_ToString(name));
+
+
+ if (segmentCount > 0) {
+ CCNxNameSegment *segment = ccnxName_GetSegment(name, segmentCount - 1);
+ if (ccnxNameSegment_GetType(segment) == CCNxNameLabelType_CHUNK) {
+ trim_segnum = 1;
+ }
+ }
+
+ hash = ccnxName_LeftMostHashCode(name, segmentCount - trim_segnum);
+
+ if (DEBUG_OUTPUT) {
+ printf("%s name %p hash %16" PRIX64 "\n", __func__, (void *) name, hash);
+ ccnxName_Display(name, 0);
+ }
+
+ // should replace this with a hash table
+ TAILQ_FOREACH(holder, &fc->sessions_head, list)
+ {
+ if (holder->basename_hash == hash) {
+ return holder;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Precondition: only called for Content Objects.
+ * If the last component is a segment number, it is ignored
+ *
+ * Match the name of the content object to an active flow control session,
+ * or return NULL if not found.
+ */
+static FcSessionHolder *
+vegas_LookupSession(VegasConnectionState *fc, TransportMessage *tm)
+{
+ assertTrue(transportMessage_IsContentObject(tm),
+ "Transport message is not a ContentObject\n");
+
+ CCNxTlvDictionary *contentObjectDictionary = transportMessage_GetDictionary(tm);
+ CCNxName *name = ccnxContentObject_GetName(contentObjectDictionary);
+
+ return vegas_LookupSessionByName(fc, name);
+}
+
+// =============================================
+
+/*
+ * Precondition: it's an interest
+ */
+static int
+vegas_HandleInterest(RtaConnection *conn, TransportMessage *tm)
+{
+ assertTrue(transportMessage_IsInterest(tm), "Transport message is not an interest");
+
+ VegasConnectionState *fc = rtaConnection_GetPrivateData(conn, FC_VEGAS);
+ CCNxTlvDictionary *interestDictionary = transportMessage_GetDictionary(tm);
+
+ // we do not modify or destroy this name
+ CCNxName *original_name = ccnxInterest_GetName(interestDictionary);
+
+ CCNxName *basename = ccnxName_Copy(original_name);
+
+ if (DEBUG_OUTPUT) {
+ printf("%s orig name %p basename %p\n", __func__, (void *) original_name, (void *) basename);
+ }
+
+ // can we decode the last component as a segment number?
+ uint64_t segnum = 0;
+ bool segnum_found = trafficTools_GetObjectSegmentFromName(basename, &segnum);
+ if (segnum_found) {
+ // it is a segment number
+ ccnxName_Trim(basename, 1);
+ }
+
+ FcSessionHolder *holder = vegas_LookupSessionByName(fc, basename);
+
+ if (holder == NULL) {
+ // create a new session
+ // This takes ownership of the basename
+ uint64_t name_hash = ccnxName_HashCode(basename);
+ holder = vegas_CreateSessionHolder(fc, conn, basename, name_hash);
+
+ CCNxInterestInterface *interestImpl = ccnxInterestInterface_GetInterface(interestDictionary);
+
+ uint32_t lifetime = ccnxInterest_GetLifetime(interestDictionary);
+
+ PARCBuffer *keyIdRestriction = ccnxInterest_GetKeyIdRestriction(interestDictionary); // might be NULL
+
+ holder->session = vegasSession_Create(fc, conn, basename, segnum,
+ interestImpl, lifetime, keyIdRestriction);
+
+ vegasSession_Start(holder->session);
+
+ rtaConnection_SendStatus(conn,
+ FC_VEGAS,
+ RTA_UP,
+ notifyStatusCode_FLOW_CONTROL_STARTED,
+ original_name,
+ NULL);
+ } else {
+ assertTrue(segnum_found, "Duplicate interest w/o segnum for existing session");
+
+ if (segnum_found) {
+ vegasSession_Seek(holder->session, segnum);
+ }
+
+ ccnxName_Release(&basename);
+ }
+
+ return 0;
+}
+
+static FcSessionHolder *
+vegas_CreateSessionHolder(VegasConnectionState *fc, RtaConnection *conn, CCNxName *basename, uint64_t name_hash)
+{
+ FcSessionHolder *holder = parcMemory_AllocateAndClear(sizeof(FcSessionHolder));
+ assertNotNull(holder, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(FcSessionHolder));
+ holder->basename_hash = name_hash;
+ holder->basename = basename;
+ holder->session = NULL;
+
+ TAILQ_INSERT_TAIL(&fc->sessions_head, holder, list);
+
+ if (DEBUG_OUTPUT) {
+ printf("%s created holder %p hash %016" PRIX64 "\n", __func__, (void *) holder, holder->basename_hash);
+ }
+ return holder;
+}
+
+/**
+ * This is called by a session when it is done
+ */
+void
+vegas_EndSession(VegasConnectionState *fc, VegasSession *session)
+{
+ FcSessionHolder *holder;
+
+ // should replace this with a hash table
+ TAILQ_FOREACH(holder, &fc->sessions_head, list)
+ {
+ if (holder->session == session) {
+ TAILQ_REMOVE(&fc->sessions_head, holder, list);
+ break;
+ }
+ }
+
+ assertNotNull(holder, "invalid state, got null holder");
+
+ rtaConnection_SendStatus(fc->parent_connection,
+ FC_VEGAS,
+ RTA_UP,
+ notifyStatusCode_FLOW_CONTROL_FINISHED,
+ holder->basename,
+ NULL);
+
+ vegasSession_Destroy(&holder->session);
+ parcMemory_Deallocate((void **) &holder);
+}
+
+static void
+vegas_SendControlPlaneResponse(RtaConnection *conn, CCNxTlvDictionary *controlDictionary, PARCEventQueue *outputQueue)
+{
+ TransportMessage *tm = transportMessage_CreateFromDictionary(controlDictionary);
+
+ transportMessage_SetInfo(tm, rtaConnection_Copy(conn), rtaConnection_FreeFunc);
+
+ if (rtaComponent_PutMessage(outputQueue, tm)) {
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, FC_VEGAS);
+ rtaComponentStats_Increment(stats, STATS_UPCALL_OUT);
+ }
+}
+
+/**
+ * @function vegas_HandleControl
+ * @abstract Process CPI reqeusts
+ * @discussion
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return true if we consumed the message, false if it should go down the stack
+ */
+static bool
+vegas_HandleControl(RtaConnection *conn, CCNxTlvDictionary *controlDictionary, PARCEventQueue *outputQueue)
+{
+ bool success = false;
+
+ if (ccnxControlFacade_IsCPI(controlDictionary)) {
+ PARCJSON *json = ccnxControlFacade_GetJson(controlDictionary);
+ if (cpi_getCPIOperation2(json) == CPI_CANCEL_FLOW) {
+ VegasConnectionState *fc = rtaConnection_GetPrivateData(conn, FC_VEGAS);
+ CCNxName *name = cpiCancelFlow_GetFlowName(json);
+
+ PARCJSON *reply = NULL;
+ FcSessionHolder *holder = vegas_LookupSessionByName(fc, name);
+ if (holder != NULL) {
+ if (DEBUG_OUTPUT) {
+ char *string = ccnxName_ToString(name);
+ printf("%s Cancelling flow %s\n", __func__, string);
+ parcMemory_Deallocate((void **) &string);
+ }
+
+ TAILQ_REMOVE(&fc->sessions_head, holder, list);
+ vegasSession_Destroy(&holder->session);
+ parcMemory_Deallocate((void **) &holder);
+
+ reply = cpiAcks_CreateAck(json);
+ } else {
+ if (DEBUG_OUTPUT) {
+ char *string = ccnxName_ToString(name);
+ printf("%s got request to cancel unknown flow %s\n", __func__, string);
+ parcMemory_Deallocate((void **) &string);
+ }
+
+ reply = cpiAcks_CreateNack(json);
+ }
+ CCNxTlvDictionary *response = ccnxControlFacade_CreateCPI(reply);
+ vegas_SendControlPlaneResponse(conn, response, outputQueue);
+ ccnxTlvDictionary_Release(&response);
+
+ parcJSON_Release(&reply);
+ ccnxName_Release(&name);
+
+ // we consume it
+ success = true;
+ }
+ }
+ return success;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/test/test_component_Vegas.c b/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/test/test_component_Vegas.c
new file mode 100644
index 00000000..2a1cfe73
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/test/test_component_Vegas.c
@@ -0,0 +1,696 @@
+/*
+ * 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.
+ */
+
+#define DEBUG_OUTPUT 0
+
+#include "../component_Vegas.c"
+#include "../vegas_Session.c"
+
+#include <sys/un.h>
+#include <strings.h>
+#include <sys/queue.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_PublicKeySignerPkcs12Store.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <ccnx/api/notify/notify_Status.h>
+
+#include <ccnx/transport/test_tools/traffic_tools.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+#include <ccnx/common/ccnx_NameSegmentNumber.h>
+
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Framework.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.c>
+#include <ccnx/transport/transport_rta/core/rta_Connection.c>
+#include <ccnx/transport/transport_rta/config/config_All.h>
+#include <ccnx/transport/test_tools/traffic_tools.h>
+
+#include "../../test/testrig_MockFramework.c"
+
+#ifndef MAXPATH
+#define MAXPATH 1024
+#endif
+
+// file descriptor for random numbers, part of Fixture
+static int randomFd;
+
+typedef struct test_data {
+ MockFramework *mock;
+ char keystore_filename[MAXPATH];
+ char keystore_password[MAXPATH];
+} TestData;
+
+static CCNxTransportConfig *
+createParams(const char *keystore_name, const char *keystore_passwd)
+{
+ assertNotNull(keystore_name, "Got null keystore name\n");
+ assertNotNull(keystore_passwd, "Got null keystore passwd\n");
+
+ CCNxStackConfig *stackConfig = apiConnector_ProtocolStackConfig(
+ testingUpper_ProtocolStackConfig(
+ vegasFlowController_ProtocolStackConfig(
+ testingLower_ProtocolStackConfig(
+ protocolStack_ComponentsConfigArgs(ccnxStackConfig_Create(),
+ apiConnector_GetName(),
+ testingUpper_GetName(),
+ vegasFlowController_GetName(),
+ testingLower_GetName(),
+ NULL)))));
+
+ CCNxConnectionConfig *connConfig = apiConnector_ConnectionConfig(
+ testingUpper_ConnectionConfig(
+ vegasFlowController_ConnectionConfig(
+ tlvCodec_ConnectionConfig(
+ testingLower_ConnectionConfig(ccnxConnectionConfig_Create())))));
+
+ publicKeySignerPkcs12Store_ConnectionConfig(connConfig, keystore_name, keystore_passwd);
+
+ CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig);
+ ccnxStackConfig_Release(&stackConfig);
+ return result;
+}
+
+static TestData *
+_commonSetup(const char *name)
+{
+ parcSecurity_Init();
+
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ sprintf(data->keystore_filename, "/tmp/keystore_%s_%d.p12", name, getpid());
+ sprintf(data->keystore_password, "12345");
+
+ unlink(data->keystore_filename);
+
+ CCNxTransportConfig *config = createParams(data->keystore_filename, data->keystore_password);
+ data->mock = mockFramework_Create(config);
+ ccnxTransportConfig_Destroy(&config);
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ mockFramework_Destroy(&data->mock);
+ unlink(data->keystore_filename);
+ parcMemory_Deallocate((void **) &data);
+
+ parcSecurity_Fini();
+}
+
+// ======================================================
+
+LONGBOW_TEST_RUNNER(Fc_Vegas)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Component);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(Fc_Vegas)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ randomFd = open("/dev/urandom", O_RDONLY);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(Fc_Vegas)
+{
+ close(randomFd);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ==============================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, vegasSession_GetFinalBlockIdFromContentObject_None);
+ LONGBOW_RUN_TEST_CASE(Local, vegasSession_GetFinalBlockIdFromContentObject_TestCases);
+
+ LONGBOW_RUN_TEST_CASE(Local, vegasSession_GetSegnumFromObject);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup(longBowTestCase_GetName(testCase)));
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ _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;
+}
+
+static CCNxTlvDictionary *
+createSignedContentObject(void)
+{
+ CCNxName *name = ccnxName_CreateFromCString("lci:/some/name");
+ PARCBuffer *payload = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(20), 11, (uint8_t *) "the payload"));
+ CCNxTlvDictionary *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+
+ PARCBuffer *keyid = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(20), 5, (uint8_t *) "keyid"));
+ ccnxValidationRsaSha256_Set(contentObject, keyid, NULL);
+ parcBuffer_Release(&keyid);
+
+ PARCBuffer *sigbits = parcBuffer_WrapCString("the signature");
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, parcBuffer_Flip(sigbits));
+ ccnxContentObject_SetSignature(contentObject, keyid, signature, NULL);
+
+ parcSignature_Release(&signature);
+ parcBuffer_Release(&sigbits);
+
+ return contentObject;
+}
+
+static CCNxTlvDictionary *
+createSignedContentObjectWithFinalBlockId(uint64_t fbid)
+{
+ CCNxTlvDictionary *obj = createSignedContentObject();
+ ccnxContentObject_SetFinalChunkNumber(obj, fbid);
+
+ return obj;
+}
+
+LONGBOW_TEST_CASE(Local, vegasSession_GetFinalBlockIdFromContentObject_None)
+{
+ CCNxTlvDictionary *contentObjectDictionary = createSignedContentObject();
+ bool success = vegasSession_GetFinalBlockIdFromContentObject(contentObjectDictionary, NULL);
+ assertFalse(success, "Should have failed getting FBID from content object");
+ ccnxTlvDictionary_Release(&contentObjectDictionary);
+}
+
+LONGBOW_TEST_CASE(Local, vegasSession_GetFinalBlockIdFromContentObject_TestCases)
+{
+ struct test_struct {
+ uint64_t value;
+ size_t encodedBytes;
+ uint8_t *encoded;
+ } test_vector[] = {
+ { .value = 0x0000000000000000ULL, .encodedBytes = 1, .encoded = (uint8_t[1]) { 0x00 } },
+ { .value = 0x0000000000000001ULL, .encodedBytes = 1, .encoded = (uint8_t[1]) { 0x01 } },
+ { .value = 0x00000000000000FFULL, .encodedBytes = 1, .encoded = (uint8_t[1]) { 0xFF } },
+ { .value = 0x0000000000000100ULL, .encodedBytes = 2, .encoded = (uint8_t[2]) { 0x01, 0x00} },
+ { .value = 0x0100000000000100ULL, .encodedBytes = 8, .encoded = (uint8_t[8]) { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00} },
+ { .value = 0x8000000000000100ULL, .encodedBytes = 8, .encoded = (uint8_t[8]) { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00} },
+ { .value = 0xFFFFFFFFFFFFFFFFULL, .encodedBytes = 8, .encoded = (uint8_t[8]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} },
+ { .value = 0, .encodedBytes = 0, .encoded = NULL }
+ };
+
+ for (int i = 0; test_vector[i].encoded != NULL; i++) {
+ CCNxTlvDictionary *signed_with_fbid = createSignedContentObjectWithFinalBlockId(test_vector[i].value);
+
+ uint64_t testvalue = -1;
+ bool success = vegasSession_GetFinalBlockIdFromContentObject(signed_with_fbid, &testvalue);
+ assertTrue(success, "Failed to get FBID from content object index %d value %016" PRIx64 "\n",
+ i,
+ test_vector[i].value)
+ {
+ ccnxTlvDictionary_Display(signed_with_fbid, 0);
+ }
+
+
+ assertTrue(testvalue == test_vector[i].value,
+ "Segment number does not match index %d value %016" PRIx64 ": got %" PRIx64 "\n",
+ i,
+ test_vector[i].value,
+ testvalue);
+
+ ccnxTlvDictionary_Release(&signed_with_fbid);
+ }
+}
+
+LONGBOW_TEST_CASE(Local, vegasSession_GetSegnumFromObject)
+{
+ struct test_struct {
+ bool valid;
+ uint64_t segnum;
+ char *uri;
+ } test_vectors[] = {
+ { .valid = false, .segnum = 0, .uri = "lci:/foo/bar" },
+ { .valid = true, .segnum = 0, .uri = "lci:/foo/" CCNxNameLabel_Chunk "=%00" },
+ { .valid = true, .segnum = 0x1020, .uri = "lci:/foo/" CCNxNameLabel_Chunk "=%10%20" },
+ { .valid = true, .segnum = 0x6162, .uri = "lci:/foo/" CCNxNameLabel_Chunk "=ab" },
+ { .valid = true, .segnum = 0x616263, .uri = "lci:/foo/" CCNxNameLabel_Chunk "=abc" },
+ { .valid = true, .segnum = 0x61626364, .uri = "lci:/foo/" CCNxNameLabel_Chunk "=abcd" },
+ { .valid = true, .segnum = 0x6162636465, .uri = "lci:/foo/" CCNxNameLabel_Chunk "=abcde" },
+ { .valid = true, .segnum = 0x616263646566, .uri = "lci:/foo/" CCNxNameLabel_Chunk "=abcdef" },
+ { .valid = true, .segnum = 0x61626364656667, .uri = "lci:/foo/" CCNxNameLabel_Chunk "=abcdefg" },
+ { .valid = true, .segnum = 0x6162636465666768, .uri = "lci:/foo/" CCNxNameLabel_Chunk "=abcdefgh" },
+ { .valid = false, .segnum = 0, .uri = NULL }
+ };
+
+ for (int i = 0; test_vectors[i].uri != NULL; i++) {
+ CCNxName *name = ccnxName_CreateFromCString(test_vectors[i].uri);
+ CCNxTlvDictionary *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, NULL);
+
+ uint64_t testSeqnum = -1;
+ int failure = vegasSession_GetSegnumFromObject(contentObject, &testSeqnum);
+
+
+
+ if (test_vectors[i].valid) {
+ assertFalse(failure, "Incorrect success index %d: got %d expected %d",
+ i, failure, test_vectors[i].valid);
+
+ assertTrue(testSeqnum == test_vectors[i].segnum, "Incorrect segnum index %d, got %" PRIu64 " expected %" PRIu64,
+ i, testSeqnum, test_vectors[i].segnum);
+ } else {
+ assertTrue(failure, "Incorrect success index %d: got %d expected %d",
+ i, failure, test_vectors[i].valid);
+ }
+
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&contentObject);
+ }
+}
+
+// ==============================================================
+
+LONGBOW_TEST_FIXTURE(Component)
+{
+ LONGBOW_RUN_TEST_CASE(Component, open_close);
+
+ // these should all be pass through
+ LONGBOW_RUN_TEST_CASE(Component, content_object_down);
+ LONGBOW_RUN_TEST_CASE(Component, control_msg_down);
+ LONGBOW_RUN_TEST_CASE(Component, interest_up);
+ LONGBOW_RUN_TEST_CASE(Component, control_msg_up);
+ LONGBOW_RUN_TEST_CASE(Component, cancel_flow);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Component)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup(longBowTestCase_GetName(testCase)));
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Component)
+{
+ _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(Component, open_close)
+{
+ // dont actually do anything. make sure no memory leaks in setup and teardown.
+}
+
+
+// ============================================
+// Passthrough messages
+
+LONGBOW_TEST_CASE(Component, content_object_down)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ TransportMessage *truth_tm = trafficTools_CreateTransportMessageWithSignedContentObject(data->mock->connection);
+
+ PARCEventQueue *in = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
+ PARCEventQueue *read = rtaProtocolStack_GetPutQueue(data->mock->stack, FC_VEGAS, RTA_UP);
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_LOWER, RTA_UP);
+
+ rtaComponent_PutMessage(in, truth_tm);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+ flow_vegas_ops.downcallRead(read, PARCEventType_Read, (void *) data->mock->stack);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+
+ TransportMessage *test_tm = rtaComponent_GetMessage(out);
+
+ assertTrue(test_tm == truth_tm,
+ "Got wrong transport message pointer, got %p expected %p",
+ (void *) test_tm,
+ (void *) truth_tm);
+
+ transportMessage_Destroy(&truth_tm);
+}
+
+LONGBOW_TEST_CASE(Component, control_msg_down)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ TransportMessage *truth_tm = trafficTools_CreateTransportMessageWithControlMessage(data->mock->connection);
+
+ PARCEventQueue *in = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
+ PARCEventQueue *read = rtaProtocolStack_GetPutQueue(data->mock->stack, FC_VEGAS, RTA_UP);
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_LOWER, RTA_UP);
+
+ rtaComponent_PutMessage(in, truth_tm);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+ flow_vegas_ops.downcallRead(read, PARCEventType_Read, (void *) data->mock->stack);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+ TransportMessage *test_tm = rtaComponent_GetMessage(out);
+
+ assertTrue(test_tm == truth_tm,
+ "Got wrong transport message pointer, got %p expected %p",
+ (void *) test_tm,
+ (void *) truth_tm);
+
+ transportMessage_Destroy(&truth_tm);
+}
+
+LONGBOW_TEST_CASE(Component, interest_up)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ TransportMessage *truth_tm = trafficTools_CreateTransportMessageWithInterest(data->mock->connection);
+
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
+ PARCEventQueue *read = rtaProtocolStack_GetPutQueue(data->mock->stack, FC_VEGAS, RTA_DOWN);
+ PARCEventQueue *in = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_LOWER, RTA_UP);
+
+ rtaComponent_PutMessage(in, truth_tm);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+ flow_vegas_ops.upcallRead(read, PARCEventType_Read, (void *) data->mock->stack);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+ TransportMessage *test_tm = rtaComponent_GetMessage(out);
+
+ assertTrue(test_tm == truth_tm,
+ "Got wrong transport message pointer, got %p expected %p",
+ (void *) test_tm,
+ (void *) truth_tm);
+
+ transportMessage_Destroy(&truth_tm);
+}
+
+LONGBOW_TEST_CASE(Component, control_msg_up)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ TransportMessage *truth_tm = trafficTools_CreateTransportMessageWithControlMessage(data->mock->connection);
+
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
+ PARCEventQueue *read = rtaProtocolStack_GetPutQueue(data->mock->stack, FC_VEGAS, RTA_DOWN);
+ PARCEventQueue *in = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_LOWER, RTA_UP);
+
+ rtaComponent_PutMessage(in, truth_tm);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+ flow_vegas_ops.upcallRead(read, PARCEventType_Read, (void *) data->mock->stack);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+ TransportMessage *test_tm = rtaComponent_GetMessage(out);
+
+ assertTrue(test_tm == truth_tm,
+ "Got wrong transport message pointer, got %p expected %p",
+ (void *) test_tm,
+ (void *) truth_tm);
+
+ transportMessage_Destroy(&test_tm);
+}
+
+// ============================================
+// These should start a flow control session
+
+/**
+ * Creates an interest w/o a segment number
+ * Sends it down the stack to the flow controller
+ * Flow controller should append segment number 0 to the interest and send that down the stack
+ */
+LONGBOW_TEST_CASE(Component, interest_down)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ TransportMessage *truth_tm = trafficTools_CreateTransportMessageWithInterest(data->mock->connection);
+
+ // If we can, add a payload to the Interest. Why not.
+ PARCBuffer *payload = NULL;
+ CCNxInterest *interest = transportMessage_GetDictionary(truth_tm);
+ CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest);
+ if (impl != NULL && impl != &CCNxInterestFacadeV1_Implementation) {
+ // V1 or greater should support Interest payloads.
+ payload = parcBuffer_WrapCString("This is a payload.");
+ impl->setPayload(interest, payload);
+ }
+
+ PARCEventQueue *in = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
+ PARCEventQueue *read = rtaProtocolStack_GetPutQueue(data->mock->stack, FC_VEGAS, RTA_UP);
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_LOWER, RTA_UP);
+
+ rtaComponent_PutMessage(in, truth_tm);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+ flow_vegas_ops.downcallRead(read, PARCEventType_Read, (void *) data->mock->stack);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+
+ // we should see a status message up the stack and interests
+ // going down the stack.
+
+
+ TransportMessage *test_tm = rtaComponent_GetMessage(in);
+ assertNotNull(test_tm, "got null transport message back up the queue, expecting status\n");
+
+ assertTrue(transportMessage_IsControl(test_tm),
+ "Transport message is not a control object")
+ {
+ ccnxTlvDictionary_Display(transportMessage_GetDictionary(test_tm), 0);
+ }
+
+ CCNxTlvDictionary *test_dict = transportMessage_GetDictionary(test_tm);
+
+ PARCJSON *json = ccnxControlFacade_GetJson(test_dict);
+
+ NotifyStatus *status = notifyStatus_ParseJSON(json);
+
+ assertNotNull(status, "Could not parse NotifyStatus JSON message");
+ assertTrue(notifyStatus_GetFiledes(status) == data->mock->connection->api_fd,
+ "Expected file descriptor %d, actual %d\n", data->mock->connection->api_fd, notifyStatus_GetFiledes(status));
+
+ assertTrue(notifyStatus_IsFlowControlStarted(status),
+ "Expected notifyStatus_IsFlowControlStarted to be true, actual code %d", notifyStatus_GetStatusCode(status));
+
+ notifyStatus_Release(&status);
+
+ transportMessage_Destroy(&test_tm);
+
+ // Read segment 0 interest
+ trafficTools_ReadAndVerifySegment(out, ccnxInterest_GetName(transportMessage_GetDictionary(truth_tm)), 0, payload);
+
+ // Now read segment 1
+ trafficTools_ReadAndVerifySegment(out, ccnxInterest_GetName(transportMessage_GetDictionary(truth_tm)), 1, payload);
+
+ if (payload != NULL) {
+ parcBuffer_Release(&payload);
+ }
+
+ transportMessage_Destroy(&truth_tm);
+}
+
+
+LONGBOW_TEST_CASE(Component, interest_down_slow_retransmit)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ TransportMessage *truth_tm = trafficTools_CreateTransportMessageWithInterest(data->mock->connection);
+
+ VegasConnectionState *fc;
+ FcSessionHolder *holder;
+
+ PARCEventQueue *in = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
+ PARCEventQueue *read = rtaProtocolStack_GetPutQueue(data->mock->stack, FC_VEGAS, RTA_UP);
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_LOWER, RTA_UP);
+
+ rtaComponent_PutMessage(in, truth_tm);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+ flow_vegas_ops.downcallRead(read, PARCEventType_Read, (void *) data->mock->stack);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+
+ // --------------------------------------
+ // Read segment 0 interest
+ CCNxTlvDictionary *interest = transportMessage_GetDictionary(truth_tm);
+
+ trafficTools_ReadAndVerifySegment(out, ccnxInterest_GetName(interest), 0, NULL);
+
+ // Now read segment 1
+ trafficTools_ReadAndVerifySegment(out, ccnxInterest_GetName(interest), 1, NULL);
+
+ // --------------------------------------
+ // now bump the time and see what happens.
+ // these are normally set in the timer sallback
+ fc = rtaConnection_GetPrivateData(data->mock->connection, FC_VEGAS);
+ holder = TAILQ_FIRST(&fc->sessions_head);
+ assertNotNull(holder, "got null session holder");
+
+ printf("*** bump time\n");
+
+ data->mock->framework->clock_ticks += 1001;
+
+ // RTO timeout will be 1 second
+ vegasSession_TimerCallback(-1, PARCEventType_Timeout, holder->session);
+ trafficTools_ReadAndVerifySegment(out, ccnxInterest_GetName(interest), 0, NULL);
+
+ transportMessage_Destroy(&truth_tm);
+}
+
+
+LONGBOW_TEST_CASE(Component, interest_down_fast_retransmit)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ TransportMessage *truth_tm = trafficTools_CreateTransportMessageWithInterest(data->mock->connection);
+
+ CCNxName *basename, *segmentname;
+ VegasConnectionState *fc;
+ FcSessionHolder *holder;
+
+ PARCEventQueue *in = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
+ PARCEventQueue *read = rtaProtocolStack_GetPutQueue(data->mock->stack, FC_VEGAS, RTA_UP);
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_LOWER, RTA_UP);
+
+ rtaComponent_PutMessage(in, truth_tm);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+ flow_vegas_ops.downcallRead(read, PARCEventType_Read, (void *) data->mock->stack);
+ rtaFramework_NonThreadedStep(data->mock->framework);
+
+ // --------------------------------------
+ // Read segment 0 interest
+ CCNxTlvDictionary *interest = transportMessage_GetDictionary(truth_tm);
+
+ trafficTools_ReadAndVerifySegment(out, ccnxInterest_GetName(interest), 0, NULL);
+
+ // Now read segment 1
+ trafficTools_ReadAndVerifySegment(out, ccnxInterest_GetName(interest), 1, NULL);
+
+ // --------------------------------------
+ // now bump the time and see what happens.
+ // these are normally set in the timer sallback
+ fc = rtaConnection_GetPrivateData(data->mock->connection, FC_VEGAS);
+ holder = TAILQ_FIRST(&fc->sessions_head);
+ assertNotNull(holder, "got null session holder");
+
+
+ data->mock->framework->clock_ticks += 20;
+ printf("*** bump time %" PRIu64 "\n", data->mock->framework->clock_ticks);
+ vegasSession_TimerCallback(-1, PARCEventType_Timeout, holder->session);
+
+ // --------------------------------------
+ // send an out-of-order content object, should see a fast retransmit
+
+ basename = ccnxName_Copy(ccnxInterest_GetName(interest));
+ segmentname = ccnxName_Copy(basename);
+
+ CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, 1);
+ ccnxName_Append(segmentname, segment);
+ ccnxNameSegment_Release(&segment);
+
+ transportMessage_Destroy(&truth_tm);
+
+ // this takes ownership of segment name
+ TransportMessage *reply =
+ trafficTools_CreateTransportMessageWithSignedContentObjectWithName(data->mock->connection,
+ segmentname, data->keystore_filename, data->keystore_password);
+
+ rtaComponent_PutMessage(out, reply);
+
+ data->mock->framework->clock_ticks += 40;
+ printf("*** bump time %" PRIu64 "\n", data->mock->framework->clock_ticks);
+ rtaFramework_NonThreadedStepCount(data->mock->framework, 5);
+ vegasSession_TimerCallback(-1, PARCEventType_Timeout, holder->session);
+
+ trafficTools_ReadAndVerifySegment(out, basename, 0, NULL);
+
+ ccnxName_Release(&segmentname);
+ ccnxName_Release(&basename);
+}
+
+/**
+ * Send an interest down the stack to start a flow controller, then send
+ * a control message to cancel it.
+ */
+LONGBOW_TEST_CASE(Component, cancel_flow)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ TransportMessage *truth_tm = trafficTools_CreateTransportMessageWithInterest(data->mock->connection);
+
+ PARCEventQueue *in = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
+
+ CCNxName *flowName = ccnxName_Acquire(ccnxInterest_GetName(transportMessage_GetDictionary(truth_tm)));
+
+ // ================================
+ // This will signal to the flow controller that it should start a flow
+ // We give up ownership of "truth_tm" at this point
+ rtaComponent_PutMessage(in, truth_tm);
+ rtaFramework_NonThreadedStepCount(data->mock->framework, 5);
+
+ // ================================
+ // we should see a status message up the stack
+
+ TransportMessage *test_tm = rtaComponent_GetMessage(in);
+ assertNotNull(test_tm, "got null transport message back up the queue, expecting status\n");
+
+ assertTrue(transportMessage_IsControl(test_tm), "Transport message is not a Control")
+ {
+ ccnxTlvDictionary_Display(transportMessage_GetDictionary(test_tm), 0);
+ }
+
+ CCNxTlvDictionary *controlDictionary = transportMessage_GetDictionary(test_tm);
+
+ PARCJSON *json = ccnxControlFacade_GetJson(controlDictionary);
+
+ NotifyStatus *status = notifyStatus_ParseJSON(json);
+ assertTrue(notifyStatus_IsFlowControlStarted(status),
+ "Expected notifyStatus_IsFlowControlStarted to be true. Actual code %d\n", notifyStatus_GetStatusCode(status));
+ notifyStatus_Release(&status);
+
+ // ================================
+ // After the notification, the flow is "started" and we can cancel it
+
+ // Now that its started, send a cancel
+ PARCJSON *cancelFlow = cpiCancelFlow_Create(flowName);
+ CCNxTlvDictionary *cancelDictionary = ccnxControlFacade_CreateCPI(cancelFlow);
+ parcJSON_Release(&cancelFlow);
+
+ TransportMessage *cancelTm = transportMessage_CreateFromDictionary(cancelDictionary);
+ transportMessage_SetInfo(cancelTm, rtaConnection_Copy(data->mock->connection), rtaConnection_FreeFunc);
+ rtaComponent_PutMessage(in, cancelTm);
+ rtaFramework_NonThreadedStepCount(data->mock->framework, 5);
+
+ // now verify that its gone
+ VegasConnectionState *fc = rtaConnection_GetPrivateData(data->mock->connection, FC_VEGAS);
+ FcSessionHolder *holder = TAILQ_FIRST(&fc->sessions_head);
+ assertNull(holder, "The session list is not empty!");
+
+ ccnxTlvDictionary_Release(&cancelDictionary);
+ transportMessage_Destroy(&test_tm);
+ ccnxName_Release(&flowName);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(Fc_Vegas);
+ exit(longBowMain(argc, argv, testRunner, NULL));
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/test/test_vegas_Session.c b/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/test/test_vegas_Session.c
new file mode 100644
index 00000000..b48e9a8a
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/test/test_vegas_Session.c
@@ -0,0 +1,672 @@
+/*
+ * 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.
+ */
+
+#define DEBUG_OUTPUT 0
+
+#include "../component_Vegas.c"
+#include "../vegas_Session.c"
+
+#include <sys/un.h>
+#include <strings.h>
+#include <sys/queue.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Framework.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.h>
+
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.c>
+#include <ccnx/transport/transport_rta/core/rta_Connection.c>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_PublicKeySignerPkcs12Store.h>
+#include <ccnx/transport/transport_rta/config/config_All.h>
+
+#include <ccnx/api/notify/notify_Status.h>
+
+#include <ccnx/transport/test_tools/traffic_tools.h>
+
+#include <ccnx/common/ccnx_ContentObject.h>
+#include <ccnx/common/internal/ccnx_ValidationFacadeV1.h>
+
+#include "../../test/testrig_MockFramework.c"
+
+#ifndef MAXPATH
+#define MAXPATH 1024
+#endif
+
+// file descriptor for random numbers, part of Fixture
+static int randomFd;
+
+typedef struct test_data {
+ MockFramework *mock;
+ char keystore_filename[MAXPATH];
+ char keystore_password[MAXPATH];
+} TestData;
+
+static CCNxTransportConfig *
+createParams(const char *keystore_name, const char *keystore_passwd)
+{
+ assertNotNull(keystore_name, "Got null keystore name\n");
+ assertNotNull(keystore_passwd, "Got null keystore passwd\n");
+
+ CCNxStackConfig *stackConfig = apiConnector_ProtocolStackConfig(
+ testingUpper_ProtocolStackConfig(
+ vegasFlowController_ProtocolStackConfig(
+ testingLower_ProtocolStackConfig(
+ protocolStack_ComponentsConfigArgs(ccnxStackConfig_Create(),
+ apiConnector_GetName(),
+ testingUpper_GetName(),
+ vegasFlowController_GetName(),
+ testingLower_GetName(),
+ NULL)))));
+
+ CCNxConnectionConfig *connConfig = apiConnector_ConnectionConfig(
+ testingUpper_ConnectionConfig(
+ vegasFlowController_ConnectionConfig(
+ testingLower_ConnectionConfig(ccnxConnectionConfig_Create()))));
+
+
+ publicKeySignerPkcs12Store_ConnectionConfig(connConfig, keystore_name, keystore_passwd);
+
+ CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig);
+ ccnxStackConfig_Release(&stackConfig);
+ return result;
+}
+
+static TestData *
+_commonSetup(const char *name)
+{
+ parcSecurity_Init();
+
+ TestData *data = parcMemory_Allocate(sizeof(TestData));
+
+ assertNotNull(data, "Got null memory from parcMemory_Allocate");
+
+ sprintf(data->keystore_filename, "/tmp/keystore_%s_%d.p12", name, getpid());
+ sprintf(data->keystore_password, "12345");
+
+ unlink(data->keystore_filename);
+
+ CCNxTransportConfig *config = createParams(data->keystore_filename, data->keystore_password);
+ data->mock = mockFramework_Create(config);
+ ccnxTransportConfig_Destroy(&config);
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ mockFramework_Destroy(&data->mock);
+ unlink(data->keystore_filename);
+
+ parcMemory_Deallocate((void **) &data);
+
+ parcSecurity_Fini();
+}
+
+
+
+// ======================================================
+
+LONGBOW_TEST_RUNNER(VegasSession)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(IterateFinalChunkNumber);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(VegasSession)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ randomFd = open("/dev/urandom", O_RDONLY);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(VegasSession)
+{
+ close(randomFd);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ==============================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, vegasSession_GetFinalBlockIdFromContentObject_None);
+ LONGBOW_RUN_TEST_CASE(Local, vegasSession_GetFinalBlockIdFromContentObject_TestCases);
+ LONGBOW_RUN_TEST_CASE(Local, vegasSession_GetSegnumFromObject);
+
+ LONGBOW_RUN_TEST_CASE(Local, vegasSession_ReceiveContentObject_InOrder_LastBlockSetsFinalId);
+ LONGBOW_RUN_TEST_CASE(Local, vegasSession_ReceiveContentObject_InOrder_FirstAndLastBlocksSetsFinalId);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup(longBowTestCase_GetName(testCase)));
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ _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;
+}
+
+static CCNxTlvDictionary *
+createSignedContentObject(void)
+{
+ CCNxName *name = ccnxName_CreateFromCString("ccnx:/some/name");
+ PARCBuffer *payload = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(20), 11, (uint8_t *) "the payload"));
+ CCNxTlvDictionary *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload);
+ parcBuffer_Release(&payload);
+ ccnxName_Release(&name);
+
+ PARCBuffer *keyid = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(20), 5, (uint8_t *) "keyid"));
+ ccnxValidationRsaSha256_Set(contentObject, keyid, NULL);
+ parcBuffer_Release(&keyid);
+
+ PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(20), 13, (uint8_t *) "the signature"));
+
+ switch (ccnxTlvDictionary_GetSchemaVersion(contentObject)) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ ccnxValidationFacadeV1_SetPayload(contentObject, sigbits);
+ break;
+ default:
+ trapNotImplemented("Unsupprted schema version in createSignedContentObject()");
+ break;
+ }
+
+ parcBuffer_Release(&sigbits);
+
+ return contentObject;
+}
+
+static CCNxTlvDictionary *
+createSignedContentObjectWithFinalBlockId(uint64_t fbid)
+{
+ CCNxTlvDictionary *obj = createSignedContentObject();
+ ccnxContentObject_SetFinalChunkNumber(obj, fbid);
+ return obj;
+}
+
+LONGBOW_TEST_CASE(Local, vegasSession_GetFinalBlockIdFromContentObject_None)
+{
+ CCNxTlvDictionary *contentObjectDictionary = createSignedContentObject();
+ bool success = vegasSession_GetFinalBlockIdFromContentObject(contentObjectDictionary, NULL);
+ assertFalse(success, "Should have failed getting FBID from content object");
+ ccnxTlvDictionary_Release(&contentObjectDictionary);
+}
+
+LONGBOW_TEST_CASE(Local, vegasSession_GetFinalBlockIdFromContentObject_TestCases)
+{
+ struct test_struct {
+ uint64_t value;
+ size_t encodedBytes;
+ uint8_t *encoded;
+ } test_vector[] = {
+ { .value = 0x0000000000000000ULL, .encodedBytes = 1, .encoded = (uint8_t[1]) { 0x00 } },
+ { .value = 0x0000000000000001ULL, .encodedBytes = 1, .encoded = (uint8_t[1]) { 0x01 } },
+ { .value = 0x00000000000000FFULL, .encodedBytes = 1, .encoded = (uint8_t[1]) { 0xFF } },
+ { .value = 0x0000000000000100ULL, .encodedBytes = 2, .encoded = (uint8_t[2]) { 0x01, 0x00} },
+ { .value = 0x0100000000000100ULL, .encodedBytes = 8, .encoded = (uint8_t[8]) { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00} },
+ { .value = 0x8000000000000100ULL, .encodedBytes = 8, .encoded = (uint8_t[8]) { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00} },
+ { .value = 0xFFFFFFFFFFFFFFFFULL, .encodedBytes = 8, .encoded = (uint8_t[8]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} },
+ { .value = 0, .encodedBytes = 0, .encoded = NULL }
+ };
+
+ for (int i = 0; test_vector[i].encoded != NULL; i++) {
+ CCNxTlvDictionary *signed_with_fbid = createSignedContentObjectWithFinalBlockId(test_vector[i].value);
+
+ uint64_t testvalue = -1;
+ bool success = vegasSession_GetFinalBlockIdFromContentObject(signed_with_fbid, &testvalue);
+ assertTrue(success, "Failed to get FBID from content object index %d value %016" PRIx64 "\n",
+ i,
+ test_vector[i].value)
+ {
+ ccnxTlvDictionary_Display(signed_with_fbid, 0);
+ }
+
+
+ assertTrue(testvalue == test_vector[i].value,
+ "Segment number does not match index %d value %016" PRIx64 ": got %" PRIx64 "\n",
+ i,
+ test_vector[i].value,
+ testvalue);
+
+ ccnxTlvDictionary_Release(&signed_with_fbid);
+ }
+}
+
+LONGBOW_TEST_CASE(Local, vegasSession_GetSegnumFromObject)
+{
+ struct test_struct {
+ bool valid;
+ uint64_t segnum;
+ char *uri;
+ } test_vectors[] = {
+ { .valid = false, .segnum = 0, .uri = "ccnx:/foo/bar" },
+ { .valid = true, .segnum = 0, .uri = "ccnx:/foo/" CCNxNameLabel_Chunk "=%00" },
+ { .valid = true, .segnum = 0x1020, .uri = "ccnx:/foo/" CCNxNameLabel_Chunk "=%10%20" },
+ { .valid = true, .segnum = 0x6162, .uri = "ccnx:/foo/" CCNxNameLabel_Chunk "=ab" },
+ { .valid = true, .segnum = 0x616263, .uri = "ccnx:/foo/" CCNxNameLabel_Chunk "=abc" },
+ { .valid = true, .segnum = 0x61626364, .uri = "ccnx:/foo/" CCNxNameLabel_Chunk "=abcd" },
+ { .valid = true, .segnum = 0x6162636465, .uri = "ccnx:/foo/" CCNxNameLabel_Chunk "=abcde" },
+ { .valid = true, .segnum = 0x616263646566, .uri = "ccnx:/foo/" CCNxNameLabel_Chunk "=abcdef" },
+ { .valid = true, .segnum = 0x61626364656667, .uri = "ccnx:/foo/" CCNxNameLabel_Chunk "=abcdefg" },
+ { .valid = true, .segnum = 0x6162636465666768, .uri = "ccnx:/foo/" CCNxNameLabel_Chunk "=abcdefgh" },
+ { .valid = false, .segnum = 0, .uri = NULL }
+ };
+
+ for (int i = 0; test_vectors[i].uri != NULL; i++) {
+ CCNxName *name = ccnxName_CreateFromCString(test_vectors[i].uri);
+ CCNxTlvDictionary *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, NULL);
+
+ uint64_t testSeqnum = -1;
+ int failure = vegasSession_GetSegnumFromObject(contentObject, &testSeqnum);
+
+
+
+ if (test_vectors[i].valid) {
+ assertFalse(failure, "Incorrect success index %d: got %d expected %d",
+ i, failure, test_vectors[i].valid);
+
+ assertTrue(testSeqnum == test_vectors[i].segnum, "Incorrect segnum index %d, got %" PRIu64 " expected %" PRIu64,
+ i, testSeqnum, test_vectors[i].segnum);
+ } else {
+ assertTrue(failure, "Incorrect success index %d: got %d expected %d",
+ i, failure, test_vectors[i].valid);
+ }
+
+ ccnxName_Release(&name);
+ ccnxTlvDictionary_Release(&contentObject);
+ }
+}
+
+
+// =================================================================
+// Tests related to the FinalBlockId and how the publisher sets it in
+// a stream of content objects
+
+#define DO_NOT_SET ((uint64_t) -1)
+#define SENTINEL ((uint64_t) -1)
+
+typedef struct test_vector {
+ uint64_t chunk;
+ uint64_t setFinalBlockId;
+ bool isLast;
+ bool interestReceived;
+ bool dataReceived;
+} TestVector;
+
+
+static void
+_verifyFlowStartNotification(TestData *data, TransportMessage *notify)
+{
+ assertNotNull(notify, "got null transport message back up the queue, expecting status\n");
+
+ assertTrue(transportMessage_IsControl(notify),
+ "Transport message is not a control object")
+ {
+ ccnxTlvDictionary_Display(transportMessage_GetDictionary(notify), 0);
+ }
+
+ CCNxTlvDictionary *test_dict = transportMessage_GetDictionary(notify);
+
+ PARCJSON *json = ccnxControlFacade_GetJson(test_dict);
+
+ NotifyStatus *status = notifyStatus_ParseJSON(json);
+
+ assertNotNull(status, "Could not parse NotifyStatus JSON message");
+ assertTrue(notifyStatus_GetFiledes(status) == data->mock->connection->api_fd,
+ "Expected file descriptor %d, actual %d\n", data->mock->connection->api_fd, notifyStatus_GetFiledes(status));
+
+ assertTrue(notifyStatus_IsFlowControlStarted(status),
+ "Expected notifyStatus_IsFlowControlStarted to be true, actual code %d", notifyStatus_GetStatusCode(status));
+
+ notifyStatus_Release(&status);
+}
+
+
+static CCNxName *
+_startFlow(TestData *data)
+{
+ TransportMessage *downInterest = trafficTools_CreateTransportMessageWithInterest(data->mock->connection);
+ CCNxName *sessionName = ccnxName_Acquire(ccnxInterest_GetName(transportMessage_GetDictionary(downInterest)));
+ PARCEventQueue *upperQueue = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
+
+ rtaComponent_PutMessage(upperQueue, downInterest);
+ rtaFramework_NonThreadedStepCount(data->mock->framework, 10);
+
+ // we should see a status message up the stack and interests
+ // going down the stack.
+
+ TransportMessage *notify = rtaComponent_GetMessage(upperQueue);
+ _verifyFlowStartNotification(data, notify);
+ transportMessage_Destroy(&notify);
+
+ return sessionName;
+}
+
+/*
+ * Caveat: this only works because we create a single session
+ */
+static VegasSession *
+_grabSession(TestData *data, CCNxName *name)
+{
+ VegasConnectionState *fc = rtaConnection_GetPrivateData(data->mock->connection, FC_VEGAS);
+
+ FcSessionHolder *holder = vegas_LookupSessionByName(fc, name);
+
+ assertNotNull(holder, "Could not find the session holder in the flow controller");
+ return holder->session;
+}
+
+/*
+ * a tick is 1 milli-second, but it could be different depending on how
+ * the framework is started
+ */
+static void
+_bumpTime(TestData *data, unsigned ticks, CCNxName *name)
+{
+ data->mock->framework->clock_ticks += ticks;
+ vegasSession_TimerCallback(-1, PARCEventType_Timeout, _grabSession(data, name));
+}
+
+static uint64_t
+_getChunkNumberFromName(const CCNxName *name)
+{
+ size_t segmentCount = ccnxName_GetSegmentCount(name);
+ CCNxNameSegment *lastSegment = ccnxName_GetSegment(name, segmentCount - 1);
+ CCNxNameLabelType nameType = ccnxNameSegment_GetType(lastSegment);
+ assertTrue(nameType == CCNxNameLabelType_CHUNK, "Wrong segment type got %d expected %d", nameType, CCNxNameLabelType_CHUNK);
+ uint64_t chunkNumber = ccnxNameSegmentNumber_Value(lastSegment);
+ return chunkNumber;
+}
+
+static TestVector *
+_getVector(TestVector *vectors, uint64_t chunkNumber)
+{
+ // find the test vector for this chunk
+ for (int i = 0; vectors[i].chunk != SENTINEL; i++) {
+ if (vectors[i].chunk == chunkNumber) {
+ return &vectors[i];
+ }
+ }
+ trapIllegalValue(chunkNumber, "Could not find chunk number in test vector");
+}
+
+static TransportMessage *
+_createReponseContentObject(CCNxName *name, uint64_t finalBlockid)
+{
+ CCNxContentObject *obj = ccnxContentObject_CreateWithNameAndPayload(name, NULL);
+ assertNotNull(obj, "Got null content object.");
+
+ if (finalBlockid != DO_NOT_SET) {
+ bool success = ccnxContentObject_SetFinalChunkNumber(obj, finalBlockid);
+ assertTrue(success, "Failed to set final chunk number");
+ }
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromContentObject(obj);
+ TransportMessage *response = transportMessage_CreateFromDictionary(message);
+
+ ccnxMetaMessage_Release(&message);
+ ccnxContentObject_Release(&obj);
+
+ return response;
+}
+
+/*
+ * Returns true if the unit test is finished
+ */
+static bool
+_respondToDownInterest(TestData *data, TestVector *vectors)
+{
+ PARCEventQueue *lowerQueue = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_LOWER, RTA_UP);
+
+ bool finished = false;
+ TransportMessage *msg = rtaComponent_GetMessage(lowerQueue);
+ if (msg) {
+ // it should be an Interest with a chunk number
+ assertTrue(transportMessage_IsInterest(msg), "Got unexpected message")
+ {
+ ccnxTlvDictionary_Display(transportMessage_GetDictionary(msg), 3);
+ }
+
+ CCNxTlvDictionary *interestDictionary = transportMessage_GetDictionary(msg);
+ CCNxName *name = ccnxInterest_GetName(interestDictionary);
+ uint64_t chunkNumber = _getChunkNumberFromName(name);
+
+ TestVector *vector = _getVector(vectors, chunkNumber);
+
+ vector->interestReceived = true;
+
+ // create a content object and set the FinalBlockId if vector says to
+ TransportMessage *response = _createReponseContentObject(name, vector->setFinalBlockId);
+ RtaConnection *connection = transportMessage_GetInfo(msg);
+ RtaConnection *connectionRef = rtaConnection_Copy(connection);
+ transportMessage_SetInfo(response, connectionRef, rtaConnection_FreeFunc);
+
+ rtaComponent_PutMessage(lowerQueue, response);
+
+ finished = vector->isLast;
+
+ transportMessage_Destroy(&msg);
+ }
+ return finished;
+}
+
+/*
+ * Returns true if received the last message
+ */
+static bool
+_consumeUpperContentObject(TestData *data, TestVector *vectors)
+{
+ PARCEventQueue *upperQueue = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
+
+ bool finished = false;
+ TransportMessage *msg = rtaComponent_GetMessage(upperQueue);
+ if (msg) {
+ // it should be a content object
+ assertTrue(transportMessage_IsContentObject(msg), "Got unexpected message")
+ {
+ ccnxTlvDictionary_Display(transportMessage_GetDictionary(msg), 3);
+ }
+
+ CCNxTlvDictionary *objectDictionary = transportMessage_GetDictionary(msg);
+ CCNxName *name = ccnxContentObject_GetName(objectDictionary);
+ uint64_t chunkNumber = _getChunkNumberFromName(name);
+
+ TestVector *vector = _getVector(vectors, chunkNumber);
+
+ // we should not have seen it before
+ assertFalse(vector->dataReceived, "Duplicate Content Object chunk %" PRIu64, chunkNumber)
+ {
+ ccnxName_Display(name, 3);
+ }
+
+ vector->dataReceived = true;
+
+ finished = vector->isLast;
+
+ transportMessage_Destroy(&msg);
+ }
+
+ return finished;
+}
+
+static void
+_runTestVector(TestData *data, TestVector vectors[])
+{
+ CCNxName *sessionName = _startFlow(data);
+
+ bool finished = false;
+
+ while (!finished) {
+ rtaFramework_NonThreadedStep(data->mock->framework);
+ finished = _respondToDownInterest(data, vectors);
+
+ rtaFramework_NonThreadedStep(data->mock->framework);
+ finished &= _consumeUpperContentObject(data, vectors);
+
+ if (!finished) {
+ _bumpTime(data, 5, sessionName);
+ }
+ }
+
+ ccnxName_Release(&sessionName);
+}
+
+/*
+ * First chunk sets final block ID, last chunk does not. Should keep reading until
+ * the real last chunk set to itself.
+ */
+LONGBOW_TEST_CASE(Local, vegasSession_ReceiveContentObject_InOrder_FirstBlockSetsLastDoesNotFinalId)
+{
+ TestVector vectors[] = {
+ { .chunk = 0, .setFinalBlockId = 5, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 1, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 2, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 3, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 4, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 5, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 6, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 7, .setFinalBlockId = 7, .isLast = true, .interestReceived = false, .dataReceived = false },
+ { .chunk = SENTINEL, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ };
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ _runTestVector(data, vectors);
+}
+
+/*
+ * FinalBlockId unset until last chunk, which sets to itself
+ */
+LONGBOW_TEST_CASE(Local, vegasSession_ReceiveContentObject_InOrder_LastBlockSetsFinalId)
+{
+ TestVector vectors[] = {
+ { .chunk = 0, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 1, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 2, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 3, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 4, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 5, .setFinalBlockId = 5, .isLast = true, .interestReceived = false, .dataReceived = false },
+ { .chunk = SENTINEL, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ };
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ _runTestVector(data, vectors);
+}
+
+/*
+ * First chunk sets FinalBlockId and last chunks, and last chunk sets it to itself
+ */
+LONGBOW_TEST_CASE(Local, vegasSession_ReceiveContentObject_InOrder_FirstAndLastBlocksSetsFinalId)
+{
+ TestVector vectors[] = {
+ { .chunk = 0, .setFinalBlockId = 7, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 1, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 2, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 3, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 4, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 5, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 6, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ { .chunk = 7, .setFinalBlockId = 7, .isLast = true, .interestReceived = false, .dataReceived = false },
+ { .chunk = SENTINEL, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false },
+ };
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ _runTestVector(data, vectors);
+}
+
+// ============================================
+
+LONGBOW_TEST_FIXTURE(IterateFinalChunkNumber)
+{
+ LONGBOW_RUN_TEST_CASE(IterateFinalChunkNumber, vegasSession_ReceiveContentObject_InOrder_FirstSetsSecondIncreasesLastSetsFinalId);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(IterateFinalChunkNumber)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(IterateFinalChunkNumber)
+{
+ 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;
+}
+
+/*
+ * First chunk sets FinalBlockId, later chunk increases it by N, then final chunk set to self.
+ *
+ * In this test, we programmatically create the TestVector array so we can run different iterations of N.
+ */
+LONGBOW_TEST_CASE(IterateFinalChunkNumber, vegasSession_ReceiveContentObject_InOrder_FirstSetsSecondIncreasesLastSetsFinalId)
+{
+ const unsigned minsize = 5;
+ const unsigned maxsize = 20;
+
+ for (unsigned size = minsize; size < maxsize; size++) {
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup(longBowTestCase_GetName(testCase)));
+
+ TestVector vectors[size];
+
+ // set initial state
+ for (int i = 0; i < size; i++) {
+ vectors[i] = (TestVector) { .chunk = i, .setFinalBlockId = DO_NOT_SET, .isLast = false, .interestReceived = false, .dataReceived = false };
+ }
+
+ // first vectors sets it to minsize
+ vectors[0].setFinalBlockId = minsize;
+
+ // minsize sets it to the end
+ vectors[minsize - 1].setFinalBlockId = size;
+
+ // last one sets it to itself
+ vectors[size - 1].setFinalBlockId = size;
+ vectors[size - 1].isLast = true;
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ _runTestVector(data, vectors);
+
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ assertTrue(outstandingAllocations == 0, "Memory leak for size %u", size);
+ }
+}
+
+
+
+// ============================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(VegasSession);
+ exit(longBowMain(argc, argv, testRunner, NULL));
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/vegas_Session.c b/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/vegas_Session.c
new file mode 100644
index 00000000..a77adc34
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/vegas_Session.c
@@ -0,0 +1,1379 @@
+/*
+ * 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 additional comments in component_Vegas.c
+ *
+ * Flow Control Algorithm
+ * =========================
+ * Based on TCP Vegas. Please read the Vegas paper. We use similar
+ * variable names to the paper. Code looks quite a bit like the linux
+ * tcp_vegas.c too.
+ *
+ * Here's the differences. In CCN, an Interest is like an ACK token, it
+ * gives the network permission to send. The node issuing Interests needs
+ * to pace them to not exceed the network capacity. This is done by
+ * observing the delay of Content Objects. If the delay grows too quickly,
+ * then we back off linearly. If the delay is not much above what we expected
+ * based on the minimum observed delay, we increase linearly.
+ *
+ * During slow start, the interest window (still called "cwnd") doubles
+ * every other RTT until we exceed the slow_start_threshold or the delay
+ * increases too much.
+ *
+ * The RTT is calculated every RTT based on the observed minimum RTT during
+ * the previous period.
+ *
+ * We use RFC6298 Retransmission Timeout (RTO) calculation methods per
+ * flow control session (object basename).
+ *
+ * Just to be clear, there are two timers working. The RTO timer is for
+ * retransmitting interests if the flow as stalled out. The Vegas RTT
+ * calculation is for congestion window calculations.
+ *
+ * We we receive an out-of-order content object, we'll check the earlier
+ * segments to see if they have passed the Vegas RTT. If so, we'll
+ * re-express the interests.
+ *
+ * Each time we re-express an Interest, we might decrese the congestion
+ * window. If the last time the interest was sent was more recent than
+ * the last time we decreased the congestion window, we'll decrease the
+ * congestion window. If the last expression of the interest was before
+ * the most recent window decrease, the window is left alone. This means
+ * we'll only decreae the window once per re-expression.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <limits.h>
+#include <sys/queue.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <parc/algol/parc_EventTimer.h>
+
+#include <ccnx/common/ccnx_NameSegmentNumber.h>
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+
+#include <ccnx/transport/common/transport_Message.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_Services.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+#include <ccnx/transport/transport_rta/components/component_Flowcontrol.h>
+#include "vegas_private.h"
+
+#include <ccnx/transport/test_tools/traffic_tools.h>
+
+#include <ccnx/common/internal/ccnx_InterestDefault.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+
+#define USE_MIN_BASE_RTT 0
+
+
+// initial congestion window of 2 interests
+#define FC_INIT_CWND 2
+
+// maximum cwnd (at 8KB/object, makes this 128 MB)
+#define FC_MAX_CWND 16384
+
+#define FC_MAX_SSTHRESH FC_MAX_CWND
+
+// initial RTT in msec (100 msec)
+#define FC_INIT_RTT_MSEC 100
+
+// initial RTO in msec
+#define FC_INIT_RTO_MSEC 1000
+
+#define FC_MSS 8704
+#define min(a, b) ((a < b) ? a : b)
+#define max(a, b) ((a > b) ? a : b)
+
+// ===========================================================
+struct vegas_connection_state;
+
+struct fc_window_entry {
+ bool valid;
+ ticks t;
+ ticks t_first_request;
+ segnum_t segnum;
+
+ // set to true on the first interest request for
+ // the segment, false on subsequent requests
+ // Needed for Karn's algorithm on RTT sampling for RTO
+ bool first_request;
+
+ // Content Object read
+ TransportMessage *transport_msg;
+};
+
+struct vegas_session {
+ RtaConnection *parent_connection;
+ RtaFramework *parent_framework;
+ VegasConnectionState *parent_fc;
+
+ // next sampling time
+ ticks next_rtt_sample;
+
+ // minimum observed RTT
+ int64_t base_RTT; // absolute minimum observed
+ int64_t min_RTT; // minimum RTT in current sample
+ int cnt_RTT; // number of RTTs seen in current sample
+ int64_t sum_RTT; // sum of RTTs
+ int slow_start_threshold;
+
+ // the currently observed RTT
+ ticks current_rtt;
+
+ // we do one detailed sample per RTT
+ bool sample_in_progress;
+ ticks sample_start;
+ uint64_t sample_segnum;
+ uint64_t sample_bytes_recevied;
+
+ // Only adjust the cwnd every 2 RTTs. This
+ // indicates if we should adjust the RTT at the
+ // end of this sampling period
+ int do_fc_this_rtt;
+
+ // circular buffer for segments
+ // tail - head (mod FC_MAX_CWND) is how may outstanding interests
+ // are in-flight. If the cwnd has been reduced, it could be larger
+ // than current_cwnd.
+ uint64_t starting_segnum; // segnum of the head
+ int window_head; // window index to read from
+ int window_tail; // window index to insert at
+
+ uint32_t current_cwnd;
+ ticks last_cwnd_adjust;
+
+ uint64_t final_segnum; // if we know the final block ID
+
+ struct fc_window_entry window[FC_MAX_CWND];
+
+ PARCEventTimer *tick_event;
+
+ // we will generate Interests with the same version as was received to start the session.
+ // Will also use the same lifetime settings as the original Interest.
+
+ CCNxInterestInterface *interestInterface;
+ uint32_t lifetime;
+ PARCBuffer *keyIdRestriction;
+ CCNxName *basename;
+ uint64_t name_hash;
+
+ uint64_t cnt_old_segments;
+ uint64_t cnt_fast_reexpress;
+
+ // These are for RTO calculation
+ ticks SRTT;
+ ticks RTTVAR;
+ ticks RTO;
+ ticks next_rto; // when the next timer expires
+
+ PARCLogLevel logLevel;
+};
+
+// Control parameters, measured in segments (tcp) or objects (ccn)
+static int alpha = 2;
+static int beta = 32;
+static int _gamma = 1;
+
+// ===========================================================
+
+
+
+static void vegasSession_ExpressInterests(VegasSession *session);
+static int vegasSession_ExpressInterestForEntry(VegasSession *session, struct fc_window_entry *entry);
+
+static void vegasSession_FastReexpress(VegasSession *session, struct fc_window_entry *ack_entry);
+static void vegasSession_ForwardObjectsInOrder(VegasSession *session);
+
+static int vegasSession_GetSegnumFromObject(CCNxTlvDictionary *contentObjectDictionary, uint64_t *segnum);
+static struct fc_window_entry *
+vegasSession_GetWindowEntry(VegasSession *session, TransportMessage *tm, uint64_t segnum);
+
+static void vegasSession_ReleaseWindowEntry(struct fc_window_entry *entry);
+static void vegasSession_RunAlgorithmOnReceive(VegasSession *session, struct fc_window_entry *entry);
+
+static void vegasSession_SetTimer(VegasSession *session, ticks tick_delay);
+static void vegasSession_SlowReexpress(VegasSession *session);
+
+// =======================================================================
+
+
+static struct fc_window_entry *
+vegasSession_GetWindowEntry(VegasSession *session, TransportMessage *tm, uint64_t segnum)
+{
+ int offset;
+ struct fc_window_entry *entry;
+
+ offset = ((segnum - session->starting_segnum) + session->window_head) % FC_MAX_CWND;
+ entry = &session->window[offset];
+
+ assertTrue(entry->valid, "Requesting window entry for invalid entry %p", (void *) entry);
+ assertTrue(segnum == entry->segnum, "Expected seqnum not equal to window entry, expected %" PRIu64 ", got %" PRIu64, segnum, entry->segnum);
+
+ if (entry->transport_msg != NULL) {
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info, __func__,
+ "session %p duplicate segment %" PRIu64 "", (void *) session, entry->segnum);
+ }
+
+ transportMessage_Destroy(&entry->transport_msg);
+ }
+
+ // store the content object
+ entry->transport_msg = tm;
+
+ return entry;
+}
+
+static int
+vegasSession_GetSegnumFromObject(CCNxTlvDictionary *contentObjectDictionary, uint64_t *segnum)
+{
+ CCNxName *name = ccnxContentObject_GetName(contentObjectDictionary);
+ assertNotNull(name, "Content Object has null name")
+ {
+ ccnxTlvDictionary_Display(contentObjectDictionary, 0);
+ }
+
+ bool success = trafficTools_GetObjectSegmentFromName(name, segnum);
+
+ if (success) {
+ return 0;
+ }
+ return -1;
+}
+
+static void
+vegasSession_ReduceCongestionWindow(VegasSession *session)
+{
+ if (session->current_cwnd <= session->slow_start_threshold) {
+ // 3/4 it
+ session->current_cwnd = session->current_cwnd / 2 + session->current_cwnd / 4;
+ } else {
+ // in linear mode
+ session->current_cwnd--;
+ }
+
+ if (session->current_cwnd < 2) {
+ session->current_cwnd = 2;
+ }
+
+ session->last_cwnd_adjust = rtaFramework_GetTicks(session->parent_framework);
+}
+
+static void
+vegasSession_RunAlgorithmOnReceive(VegasSession *session, struct fc_window_entry *entry)
+{
+ ticks now;
+ int64_t fc_rtt;
+
+ now = rtaFramework_GetTicks(session->parent_framework);
+
+ // perform statistics updates.
+
+ // If the codec did not include the raw message, we cannot increment the bytes counter
+ PARCBuffer *wireFormat = ccnxWireFormatMessage_GetWireFormatBuffer(transportMessage_GetDictionary(entry->transport_msg));
+
+ if (wireFormat) {
+ session->sample_bytes_recevied += parcBuffer_Remaining(wireFormat);
+ }
+
+
+ /* add +1 so never have 0 RTT */
+ fc_rtt = ((int64_t) now - (int64_t) entry->t_first_request) + 1;
+ if (fc_rtt <= 0) {
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Error)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Error, __func__,
+ "session %p sock %3d : recv segment %" PRIu64 " with negative RTT, t = %" PRIu64 "",
+ (void *) session,
+ rtaConnection_GetConnectionId(session->parent_connection),
+ entry->segnum,
+ entry->t);
+ }
+
+ return;
+ }
+
+ /* record the absolute minimum RTT ever seen */
+ if (fc_rtt < session->base_RTT) {
+ session->base_RTT = fc_rtt;
+ }
+
+ /* find the minimum RTT for the sample period */
+ session->min_RTT = min(session->min_RTT, fc_rtt);
+ session->cnt_RTT++;
+ session->sum_RTT += fc_rtt;
+
+ // calculate RTO as per RFC6298
+ if (entry->first_request) {
+ if (session->SRTT == 0) {
+ // this is the first one, so do 2.2
+ session->SRTT = fc_rtt;
+ session->RTTVAR = fc_rtt >> 1;
+ session->RTO = session->SRTT +
+ max(rtaFramework_UsecToTicks(1000000), 4 * session->RTTVAR);
+ } else {
+ // RTTVAR <- (1 - beta) * RTTVAR + beta * |SRTT - R'|
+ // using beta = 1/4, so we want 3/4 * RTTVAR
+ int64_t abs = ((int64_t) session->SRTT - (int64_t) fc_rtt);
+
+ if (abs < 0) {
+ abs = -1 * abs;
+ }
+
+ session->RTTVAR = ((session->RTTVAR >> 1) + (session->RTTVAR >> 2)) + (abs >> 2);
+
+ // SRTT <- (1 - alpha) * SRTT + alpha * R'
+ // using alpha = 1/8 and (1-alpha) = 1/2 + 1/4 + 1/8 = 7/8
+ session->SRTT = (session->SRTT >> 1) + (session->SRTT >> 2) + (session->SRTT >> 3) + (abs >> 3);
+
+ session->RTO = session->SRTT +
+ max(rtaFramework_UsecToTicks(1000000), 4 * session->RTTVAR);
+ }
+ }
+
+ // we received a packet :) yay.
+ // we get to extend the RTO expiry
+ session->next_rto = now + session->RTO;
+}
+
+/*
+ * called inside workq_mutex lock.
+ * After we deliver each segment, we increment session->starting_segnum. After we deliver the
+ * the terminal segement of a stream, session->starting_segnum will be 1 past the final block id.
+ */
+static void
+vegasSession_ForwardObjectsInOrder(VegasSession *session)
+{
+ while (session->window_head != session->window_tail) {
+ struct fc_window_entry *entry = &session->window[ session->window_head ];
+
+ // sanity checks
+ assertTrue(entry->valid, "Window entry %p for window_head index %u", (void *) entry, session->window_head);
+ assertTrue(entry->segnum == session->starting_segnum,
+ "Expected seqnum not equal to window entry, expected %" PRIu64 ", got %" PRIu64,
+ session->starting_segnum,
+ entry->segnum);
+
+ if (entry->transport_msg != NULL) {
+ PARCEventQueue *out = rtaComponent_GetOutputQueue(session->parent_connection, FC_VEGAS, RTA_UP);
+ RtaComponentStats *stats = rtaConnection_GetStats(session->parent_connection, FC_VEGAS);
+
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug, __func__,
+ "session %p fd %d forward segment %" PRIu64 " up stack",
+ (void *) session,
+ rtaConnection_GetConnectionId(session->parent_connection),
+ entry->segnum);
+ }
+
+ if (rtaComponent_PutMessage(out, entry->transport_msg)) {
+ // if we successfully put the message up the stack, null
+ // the entry so the transport message will not be destroyed
+ // when this window entry is released.
+ entry->transport_msg = NULL;
+ rtaComponentStats_Increment(stats, STATS_UPCALL_OUT);
+ }
+
+ vegasSession_ReleaseWindowEntry(entry);
+ session->starting_segnum++;
+ session->window_head = (session->window_head + 1) % FC_MAX_CWND;
+ } else {
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug, __func__,
+ "session %p fd %d no message segment %" PRIu64 ", no more in order messages",
+ rtaConnection_GetConnectionId(session->parent_connection),
+ entry->segnum);
+ }
+
+ return;
+ }
+ }
+}
+
+static int
+fc_ssthresh(VegasSession *session)
+{
+ return min(session->slow_start_threshold, session->current_cwnd - 1);
+}
+
+/**
+ * Slow-start increase, double the cwnd
+ */
+static void
+fc_slow_start(VegasSession *session)
+{
+ session->last_cwnd_adjust = rtaFramework_GetTicks(session->parent_framework);
+ session->current_cwnd = session->current_cwnd << 1;
+}
+
+static
+int
+fc_in_cwnd_reduction(VegasSession *session)
+{
+ return 0;
+}
+
+/*
+ * Similar to the tcp_current_ssthresh. If cwnd > ssthresh, then
+ * increase ssthres to 1/2 to cwnd, except if we're in a cwnd reduction
+ * period.
+ */
+static inline uint32_t
+fc_current_ssthresh(VegasSession *session)
+{
+ if (fc_in_cwnd_reduction(session)) {
+ return session->slow_start_threshold;
+ } else {
+ return max(session->slow_start_threshold,
+ ((session->current_cwnd >> 1) +
+ (session->current_cwnd >> 2)));
+ }
+}
+
+static void
+vegasSession_CongestionAvoidanceDebug(VegasSession *session, ticks now)
+{
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug)) {
+ ticks diff = 0;
+
+ if (session->min_RTT != INT_MAX) {
+ diff = session->current_cwnd * (session->min_RTT - session->base_RTT) / session->base_RTT;
+ }
+
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug, __func__,
+ "session %p do_cong %d currentRTT %5" PRIu64 " cntRTT %3d minRTT %5" PRId64 " baseRTT %5" PRId64 " cwnd %3d next %8" PRIu64 " SRTT %" PRIu64 " RTO %" PRIu64 " oldsegs %" PRIu64 " fast %" PRIu64 " diff %" PRIu64 " allocs %u",
+ (void *) session,
+ session->do_fc_this_rtt,
+ session->current_rtt,
+ session->cnt_RTT,
+ session->min_RTT == INT_MAX ? 0 : session->min_RTT,
+ session->base_RTT == INT_MAX ? 0 : session->base_RTT,
+ session->current_cwnd,
+ session->next_rtt_sample,
+ session->SRTT,
+ session->RTO,
+ session->cnt_old_segments,
+ session->cnt_fast_reexpress,
+ diff,
+ parcMemory_Outstanding());
+ }
+}
+
+static void
+vegasSession_LossBasedAvoidance(VegasSession *session)
+{
+ session->current_rtt = session->current_rtt * 2;
+ if (session->current_rtt > 4000) {
+ session->current_rtt = 4000;
+ }
+}
+
+/**
+ * This is the Vegas algorithm
+ */
+static void
+vegasSession_TimeBasedAvoidance(VegasSession *session)
+{
+ ticks rtt, diff;
+ uint64_t target_cwnd;
+
+ rtt = session->min_RTT;
+
+ /*
+ * calculate the target cwnd in segments
+ */
+ target_cwnd = session->current_cwnd * session->base_RTT / rtt;
+
+ diff = session->current_cwnd * (rtt - session->base_RTT) / session->base_RTT;
+
+ if ((diff > _gamma && session->current_cwnd <= session->slow_start_threshold)) {
+ /* If we're in slow start and going too fast, slow down */
+ session->current_cwnd = min(session->current_cwnd, (uint32_t) target_cwnd + 1);
+ session->slow_start_threshold = fc_ssthresh(session);
+ session->last_cwnd_adjust = rtaFramework_GetTicks(session->parent_framework);
+ } else if (session->current_cwnd <= session->slow_start_threshold) {
+ /* Slow start */
+ fc_slow_start(session);
+ } else {
+ /* Congestion avoidance. */
+
+ // if (diff > beta || session->cnt_old_segments ) {
+ if (diff > beta) {
+ /* The old window was too fast, so
+ * we slow down.
+ */
+
+ session->current_cwnd--;
+ session->slow_start_threshold = fc_ssthresh(session);
+ session->last_cwnd_adjust = rtaFramework_GetTicks(session->parent_framework);
+ } else if (diff < alpha) {
+ /* room to grow */
+ session->current_cwnd++;
+ session->last_cwnd_adjust = rtaFramework_GetTicks(session->parent_framework);
+ } else {
+ /* middle ground, no changes necessary */
+ }
+ }
+
+ if (session->current_cwnd < 2) {
+ session->current_cwnd = 2;
+ } else if (session->current_cwnd > FC_MAX_CWND) {
+ session->current_cwnd = FC_MAX_CWND;
+ }
+
+ session->slow_start_threshold = fc_current_ssthresh(session);
+}
+
+static void
+vegasSession_CongestionAvoidance(VegasSession *session)
+{
+ ticks now = rtaFramework_GetTicks(session->parent_framework);
+
+ vegasSession_CongestionAvoidanceDebug(session, now);
+
+ if (session->do_fc_this_rtt) {
+ if (session->cnt_RTT <= 2) {
+ vegasSession_LossBasedAvoidance(session);
+ } else {
+ vegasSession_TimeBasedAvoidance(session);
+ }
+
+ session->do_fc_this_rtt = 0;
+ } else {
+ session->do_fc_this_rtt = 1;
+ }
+
+ // Now finish up the statistics and setup for next RTT interval
+
+ session->next_rtt_sample = now + session->current_rtt;
+
+ // low-pass filter the base_RTT from the min_RTT
+ // base_RTT = 15/16 base_RTT + 1/16 min_RTT = (240 * base_RTT + 16 * min_RTT ) / 256
+
+ if (!USE_MIN_BASE_RTT && (session->cnt_RTT > 0)) {
+ session->base_RTT = (240 * session->base_RTT + 16 * session->min_RTT) >> 8;
+ if (session->base_RTT == 0) {
+ session->base_RTT = 1;
+ }
+ }
+
+ // Smooth the RTT for (3 * current + 1 * minimum) / 4
+
+ if (session->cnt_RTT > 0) {
+ session->current_rtt = (12 * session->current_rtt + 4 * session->min_RTT) >> 4;
+ }
+
+ session->current_rtt = max(session->current_rtt, FC_INIT_RTT_MSEC);
+
+ // reset stats
+ session->sample_bytes_recevied = 0;
+ session->min_RTT = INT_MAX;
+ session->cnt_RTT = 0;
+ session->cnt_old_segments = 0;
+ session->cnt_fast_reexpress = 0;
+ session->sum_RTT = 0;
+
+ vegasSession_CongestionAvoidanceDebug(session, now);
+}
+
+/**
+ * Slow (course grain) retransmission due to RTO expiry.
+ * Re-express the first segment of the window.
+ */
+static
+void
+vegasSession_SlowReexpress(VegasSession *session)
+{
+ struct fc_window_entry *entry = &session->window[ session->window_head ];
+
+ assertTrue(entry->valid, "entry %p segnum %" PRIu64 " invalid state, in window but not valid",
+ (void *) entry, entry->segnum);
+
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info, __func__,
+ "Session %p conn %p RTO re-expression for segnum %" PRIu64 "",
+ (void *) session, (void *) session->parent_connection, entry->segnum);
+ }
+
+ entry->first_request = false;
+ vegasSession_ExpressInterestForEntry(session, entry);
+}
+
+/**
+ * Do fast retransmissions based on SRTT smoothed estimate.
+ * ack_entry is the entry for a content object we just received. Look earlier segments
+ * and if they were asked for more than SRTT ago, ask again.
+ */
+static void
+vegasSession_FastReexpress(VegasSession *session, struct fc_window_entry *ack_entry)
+{
+ ticks now = rtaFramework_GetTicks(session->parent_framework);
+ int64_t delta;
+ uint64_t segnum;
+ uint64_t top_segnum;
+
+ // This method is called after forward_in_order, so it's possible that
+ // ack_entry is no longer valid, meaning we've moved the window past it.
+ // In that case, we're done.
+ if (ack_entry->valid == false) {
+ return;
+ }
+
+ // we don't retransmit beyond the current cwnd. ack_entry might be outside
+ // the cwnd.
+
+ top_segnum = min(ack_entry->segnum, session->starting_segnum + session->current_cwnd);
+
+ for (segnum = session->starting_segnum; segnum < top_segnum; segnum++) {
+ int index = (session->window_head + (segnum - session->starting_segnum)) % FC_MAX_CWND;
+ delta = (int64_t) now - ((int64_t) session->window[index].t + (int64_t) session->SRTT);
+
+ // allow up to -1 slack, because the RunAlgorithm adds +1 to fc_rtt.
+ if (delta >= -1) {
+ // we have past the SRTT timeout
+
+ // if we last re-transmitted him since the last cwnd adjustment, adjust again
+ if ((int64_t) session->window[index].t - (int64_t) session->last_cwnd_adjust >= 0) {
+ vegasSession_ReduceCongestionWindow(session);
+ }
+
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info, __func__,
+ "session %p conn %p RTO re-expression for segnum %" PRIu64 "",
+ (void *) session, (void *) session->parent_connection, session->window[index].segnum);
+ }
+
+ session->window[index].first_request = false;
+ session->cnt_fast_reexpress++;
+ vegasSession_ExpressInterestForEntry(session, &session->window[index]);
+ }
+ }
+}
+
+/**
+ * Generates an Interest message for the window entry.
+ *
+ * No side effects, apart from putting on Interest on the down queue.
+ * If the down direction is blocked, this function will not put an interest in the down queue. It will
+ * look like a lost interest to the flow controller, which should cause the flow controller to slow down.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static int
+vegasSession_ExpressInterestForEntry(VegasSession *session, struct fc_window_entry *entry)
+{
+ if (!rtaConnection_BlockedDown(session->parent_connection)) {
+ ticks now = rtaFramework_GetTicks(session->parent_framework);
+ PARCEventQueue *q_out;
+ TransportMessage *tm_out;
+ CCNxName *chunk_name;
+
+ entry->t = now;
+
+ chunk_name = ccnxName_Copy(session->basename);
+
+ CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, entry->segnum);
+ ccnxName_Append(chunk_name, segment);
+ ccnxNameSegment_Release(&segment);
+
+ assertNotNull(session->interestInterface, "Got a NULL interestInterface. Should not happen.");
+
+ CCNxTlvDictionary *interestDictionary =
+ session->interestInterface->create(chunk_name,
+ session->lifetime,
+ NULL, // ppkid
+ NULL, // content object hash
+ CCNxInterestDefault_HopLimit);
+
+ if (session->keyIdRestriction != NULL) {
+ session->interestInterface->setKeyIdRestriction(interestDictionary, session->keyIdRestriction);
+ }
+
+ tm_out = transportMessage_CreateFromDictionary(interestDictionary);
+ transportMessage_SetInfo(tm_out, rtaConnection_Copy(session->parent_connection), rtaConnection_FreeFunc);
+
+ q_out = rtaComponent_GetOutputQueue(session->parent_connection, FC_VEGAS, RTA_DOWN);
+
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug)) {
+ char *string = ccnxName_ToString(chunk_name);
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug, __func__,
+ "session %p entry %p segname %p segnum %" PRIu64 " %s sent",
+ (void *) session,
+ (void *) entry,
+ (void *) chunk_name,
+ entry->segnum,
+ string);
+ parcMemory_Deallocate((void **) &string);
+ }
+
+ ccnxTlvDictionary_Release(&interestDictionary);
+ ccnxName_Release(&chunk_name);
+
+ if (rtaComponent_PutMessage(q_out, tm_out)) {
+ rtaComponentStats_Increment(rtaConnection_GetStats(session->parent_connection, FC_VEGAS),
+ STATS_DOWNCALL_OUT);
+ }
+ } else {
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info)) {
+ CCNxName *segment_name = ccnxName_Copy(session->basename);
+ ccnxName_Append(segment_name, ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, entry->segnum));
+ char *string = ccnxName_ToString(segment_name);
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info, __func__,
+ "session %p entry %p segname %p segnum %" PRIu64 " %s SUPPRESSED BLOCKED DOWN QUEUE",
+ (void *) session,
+ (void *) entry,
+ (void *) segment_name,
+ entry->segnum,
+ string);
+ parcMemory_Deallocate((void **) &string);
+ ccnxName_Release(&segment_name);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Express interests out to the max allowed by the cwnd. This function will operate
+ * even if the down queue is blocked. Those interests will be treated as lost, which will cause
+ * the flow controller to slow down.
+ */
+static void
+vegasSession_ExpressInterests(VegasSession *session)
+{
+ ticks now = rtaFramework_GetTicks(session->parent_framework);
+
+ // how many interests are currently outstanding?
+ int wsize = session->window_tail - session->window_head;
+ if (wsize < 0) {
+ wsize += FC_MAX_CWND;
+ }
+
+ // if we know the FBID, don't ask for anything beyond that
+ while (wsize < session->current_cwnd && (wsize + session->starting_segnum <= session->final_segnum)) {
+ // expreess them
+ struct fc_window_entry *entry = &session->window[session->window_tail];
+
+ assertFalse(entry->valid,
+ "Window entry %d marked as valid, but its outside the cwind!",
+ session->window_tail);
+
+ session->window_tail = (session->window_tail + 1) % FC_MAX_CWND;
+
+ memset(entry, 0, sizeof(struct fc_window_entry));
+
+ entry->valid = true;
+ entry->segnum = session->starting_segnum + wsize;
+ entry->first_request = true;
+ entry->t_first_request = now;
+
+ if (session->sample_in_progress == 0) {
+ // make this interest the sample for the RTT
+ session->sample_in_progress = true;
+ session->sample_segnum = entry->segnum;
+ session->sample_start = now;
+ session->sample_bytes_recevied = 0;
+ }
+
+ vegasSession_ExpressInterestForEntry(session, entry);
+
+ wsize++;
+ }
+}
+
+/*
+ * This is dispatched from the event loop, so its a loosely accurate time
+ */
+static void
+vegasSession_TimerCallback(int fd, PARCEventType what, void *user_data)
+{
+ VegasSession *session = (VegasSession *) user_data;
+ int64_t delta;
+ ticks now;
+
+ assertTrue(what & PARCEventType_Timeout, "%s got unknown signal %d", __func__, what);
+
+ now = rtaFramework_GetTicks(session->parent_framework);
+ delta = ((int64_t) now - (int64_t) session->next_rtt_sample);
+
+ if (delta >= 0) {
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug, __func__,
+ "Session %p processing timer, delta %" PRId64,
+ (void *) session, delta);
+ }
+
+ // This entry is ready for processing
+ vegasSession_CongestionAvoidance(session);
+
+ // set the next timer
+ vegasSession_SetTimer(session, session->current_rtt);
+ } else {
+ vegasSession_SetTimer(session, -1 * delta);
+ }
+
+ // check for retransmission
+ delta = ((int64_t) now - (int64_t) session->next_rto);
+ if (delta >= 0) {
+ // Do this once per RTO
+ vegasSession_SlowReexpress(session);
+
+ // we're now in a doubling regeme. Reset the
+ // moving average and double the RTO.
+ session->SRTT = 0;
+ session->RTTVAR = 0;
+ session->RTO = session->RTO * 2;
+ session->next_rto = now + session->RTO;
+ }
+}
+
+/**
+ * precondition: the entry is valid
+ */
+static void
+vegasSession_ReleaseWindowEntry(struct fc_window_entry *entry)
+{
+ assertTrue(entry->valid, "Called on invalid window entry");
+ if (!entry->valid) {
+ return;
+ }
+
+ if (entry->transport_msg != NULL) {
+ transportMessage_Destroy(&entry->transport_msg);
+ }
+ entry->valid = false;
+}
+
+static void
+vegasSession_SetTimer(VegasSession *session, ticks tick_delay)
+{
+ struct timeval timeout;
+ uint64_t usec = rtaFramework_TicksToUsec(tick_delay);
+ const unsigned usec_per_sec = 1000000;
+
+ timeout.tv_sec = usec / usec_per_sec;
+ timeout.tv_usec = (int) (usec - timeout.tv_sec * usec_per_sec);
+
+ // this replaces any prior events
+ parcEventTimer_Start(session->tick_event, &timeout);
+
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug, __func__,
+ "session %p tick_delay %" PRIu64 " timeout %.6f",
+ (void *) session,
+ tick_delay,
+ timeout.tv_sec + 1E-6 * timeout.tv_usec);
+ }
+}
+
+// =============================================
+// Private API
+
+/**
+ * Unsets the final segment number indicating we do not know the value
+ *
+ * Sets the final segment number to the maximum possible value, which effectively
+ * lets us run off to infinity.
+ *
+ * @param [in] session An allocated vegas session
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+_vegasSession_UnsetFinalSegnum(VegasSession *session)
+{
+ session->final_segnum = ULLONG_MAX;
+}
+
+VegasSession *
+vegasSession_Create(VegasConnectionState *fc, RtaConnection *conn, CCNxName *basename, segnum_t begin,
+ CCNxInterestInterface *interestInterface, uint32_t lifetime, PARCBuffer *keyIdRestriction)
+{
+ assertNotNull(conn, "Called with null connection");
+ assertNotNull(basename,
+ "conn %p connid %u called with null basename",
+ (void *) conn,
+ rtaConnection_GetConnectionId(conn));
+
+ if (conn == NULL || basename == NULL) {
+ return NULL;
+ }
+
+ VegasSession *session = parcMemory_AllocateAndClear(sizeof(VegasSession));
+ assertNotNull(session, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(VegasSession));
+ session->parent_connection = conn;
+ session->parent_framework = rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn));
+ session->interestInterface = interestInterface;
+ session->lifetime = lifetime;
+ session->basename = basename;
+ if (keyIdRestriction != NULL) {
+ session->keyIdRestriction = parcBuffer_Acquire(keyIdRestriction);
+ }
+ session->parent_fc = fc;
+
+ session->tick_event = parcEventTimer_Create(rtaFramework_GetEventScheduler(session->parent_framework), 0, vegasSession_TimerCallback, (void *) session);
+
+ session->starting_segnum = 0;
+ session->current_cwnd = FC_INIT_CWND;
+ session->min_RTT = INT_MAX;
+ session->base_RTT = INT_MAX;
+ session->do_fc_this_rtt = 0;
+ session->current_rtt = rtaFramework_UsecToTicks(FC_INIT_RTT_MSEC * 1000);
+ session->slow_start_threshold = FC_MAX_SSTHRESH;
+
+ session->SRTT = 0;
+ session->RTTVAR = 0;
+ session->RTO = rtaFramework_UsecToTicks(FC_INIT_RTO_MSEC * 1000);
+ session->next_rto = ULLONG_MAX;
+ session->cnt_old_segments = 0;
+ session->cnt_fast_reexpress = 0;
+
+ _vegasSession_UnsetFinalSegnum(session);
+
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Notice)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Notice, __func__,
+ "session %p initialized connid %u ",
+ (void *) session,
+ rtaConnection_GetConnectionId(conn));
+ }
+ return session;
+}
+
+static void
+vegasSession_Close(VegasSession *session)
+{
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Notice)) {
+ char *p = ccnxName_ToString(session->basename);
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Notice, __func__,
+ "session %p close starting segnum %" PRIu64 " final chunk ID %" PRIu64 " for name %s",
+ (void *) session, session->starting_segnum, session->final_segnum, p);
+ parcMemory_Deallocate((void **) &p);
+ }
+
+ ccnxName_Release(&session->basename);
+
+ while (session->window_head != session->window_tail) {
+ struct fc_window_entry *entry = &session->window[ session->window_head ];
+
+ // sanity checks
+ assertTrue(entry->valid, "connid %u session %p entry %d in window but not valid",
+ rtaConnection_GetConnectionId(session->parent_connection),
+ (void *) session,
+ session->window_head);
+
+ if (entry->valid) {
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug)) {
+ char *p = ccnxName_ToString(session->basename);
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug, __func__,
+ "session %p releasing window entry %d", (void *) session, session->window_head);
+ parcMemory_Deallocate((void **) &p);
+ }
+
+ vegasSession_ReleaseWindowEntry(entry);
+ }
+
+ session->window_head = (session->window_head + 1) % FC_MAX_CWND;
+ }
+}
+
+void
+vegasSession_Destroy(VegasSession **sessionPtr)
+{
+ VegasSession *session;
+
+ assertNotNull(sessionPtr, "Called with null double pointer");
+ session = *sessionPtr;
+
+ if (session->keyIdRestriction != NULL) {
+ parcBuffer_Release(&session->keyIdRestriction);
+ }
+
+ vegasSession_Close(session);
+
+ parcEventTimer_Destroy(&(session->tick_event));
+ parcMemory_Deallocate((void **) &session);
+ sessionPtr = NULL;
+}
+
+int
+vegasSession_Start(VegasSession *session)
+{
+ ticks now = rtaFramework_GetTicks(session->parent_framework);
+
+ // express the initial interests
+ vegasSession_ExpressInterests(session);
+
+ session->next_rtt_sample = now - 1;
+ session->next_rto = now + session->RTO;
+
+ // put it on the work queue for procesing
+
+ vegasSession_SetTimer(session, session->current_rtt);
+
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info, __func__,
+ "Session %p start", (void *) session);
+ }
+
+ return 0;
+}
+
+int
+vegasSession_Pause(VegasSession *session)
+{
+ trapNotImplemented("vegasSession_Pause");
+}
+
+int
+vegasSession_Resume(VegasSession *session)
+{
+ trapNotImplemented("vegasSession_Resume");
+}
+
+int
+vegasSession_Seek(VegasSession *session, segnum_t absolutePosition)
+{
+ trapNotImplemented("vegasSession_See)");
+}
+
+/**
+ * Retrieves the final block ID from the content object
+ *
+ * Retreives the final block ID from the object, if it exists, and returns it in
+ * an output parameter. Returns true if found and returned, false otherwise.
+ *
+ * @param [in] obj The Content Object to get the FBID form
+ * @param [out] output Pointer to the seqnum ouptut
+ *
+ * @return true If the content object contained a FBID and the output set
+ * @return false If there is no FBID in the content object
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+vegasSession_GetFinalBlockIdFromContentObject(CCNxTlvDictionary *obj, uint64_t *output)
+{
+ bool result = false;
+ if (ccnxContentObject_HasFinalChunkNumber(obj)) {
+ *output = ccnxContentObject_GetFinalChunkNumber(obj);
+ result = true;
+ }
+ return result;
+}
+
+/**
+ * Sets the final block id in the session based on the signed info
+ *
+ * If the final block id exists in the signed info, set the session's FBID.
+ *
+ * Rules on FinalChunkNumber:
+ *
+ * 1) The “final chunk” of a stream is identified by a content object having a FinalChunkNumber
+ * set in its metadata that equals the chunk number in its name.
+ *
+ * 2) An application may set the FinalChunkNumber early to let a receiver know when the end is coming. These early advisories are not binding.
+ *
+ * 3) If the application has ever set the FinalChunkNumber it may not decrease it. If the actual end happens before a previous advisory,
+ * the application must publish no-payload content objects such that Rule #1 is satisfied
+ *
+ *
+ * @param [in,out] session The Vegas session
+ * @param [in] obj The signed content object to get the FBID from
+ * @param [in] nameChunkNumber is the chunk number in the name
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+vegasSession_SetFinalBlockId(VegasSession *session, CCNxTlvDictionary *contentObjectDictionary, uint64_t nameChunkNumber)
+{
+ // Get the FinalChunkNumber out of the metadata and update our notion of it
+ uint64_t finalChunkNumber;
+ if (vegasSession_GetFinalBlockIdFromContentObject(contentObjectDictionary, &finalChunkNumber)) {
+ session->final_segnum = finalChunkNumber;
+
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info, __func__,
+ "Session %p finalChunkNumber %" PRIu64, (void *) session, session->final_segnum);
+ }
+ } else {
+ // There is no final chunk number in the metadata. If the nameChunkNumber == session->final_seqnum, then
+ // our idea of the final_seqnum is wrong and we should unset it as the producer did not actually close
+ // the stream when they said they would
+
+ if (session->final_segnum == nameChunkNumber) {
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Warning)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Warning, __func__,
+ "Session %p finalChunkNumber %" PRIu64 " not set in final chunk, resetting",
+ (void *) session, session->final_segnum);
+ }
+
+ _vegasSession_UnsetFinalSegnum(session);
+ }
+ }
+}
+
+/**
+ * We received a duplicate segment from before the start of the current congestion window
+ *
+ *
+ * If we receive a segment from before the start of the current congestion window, then it
+ * must be a duplicate (we don't have skip forward implemented). Reduce the congestion window size.
+ * We only reduce the window once per RTT interval no matter how many early duplicates we get.
+ *
+ * @param [in,out] session The Vegas session to reduce the window of.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+vegasSession_ReceivedBeforeWindowStart(VegasSession *session, uint64_t segnum)
+{
+ // once per cwnd, reduce the window on out-of-order
+ if (session->cnt_old_segments == 0) {
+ vegasSession_ReduceCongestionWindow(session);
+ }
+
+ session->cnt_old_segments++;
+
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug, __func__,
+ "Session %p connid %3u : recv old segment %" PRIu64 ", starting is %" PRIu64 ", cnt %" PRIu64 "",
+ (void *) session,
+ rtaConnection_GetConnectionId(session->parent_connection),
+ segnum,
+ session->starting_segnum,
+ session->cnt_old_segments);
+ }
+}
+
+static void
+vegasSession_SendMoreInterests(VegasSession *session, struct fc_window_entry *entry)
+{
+ // This will check if there's any earlier segments whose
+ // RTT has expired and will re-ask for them. This is the
+ // out-of-order fast retransmit.
+ vegasSession_FastReexpress(session, entry);
+
+ // have we finished?
+ if (session->starting_segnum < session->final_segnum) {
+ // express more interests if we have the window for it
+ vegasSession_ExpressInterests(session);
+ } else
+ if (session->starting_segnum > session->final_segnum) {
+ // if starting_segment > final_segnum it means that we have delivered the last
+ // segment up the stack.
+
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info, __func__,
+ "Session %p connid %u starting_segnum %" PRIu64 ", final_segnum %" PRIu64 ", FINAL SEGMENT DELIVERED, CLOSING",
+ (void *) session,
+ rtaConnection_GetConnectionId(session->parent_connection),
+ session->starting_segnum,
+ session->final_segnum);
+ }
+
+ parcEventTimer_Stop(session->tick_event);
+ vegas_EndSession(session->parent_fc, session);
+ }
+ // else session->starting_segnum == session->final_segnum, we're not done yet.
+}
+
+static CCNxName *
+vegasSession_GetNameFromTransportMessage(TransportMessage *tm)
+{
+ CCNxName *name = NULL;
+ CCNxTlvDictionary *dictionary = transportMessage_GetDictionary(tm);
+ switch (ccnxTlvDictionary_GetSchemaVersion(dictionary)) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ name = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+ break;
+
+ default:
+ break;
+ }
+ return name;
+}
+
+
+
+int
+vegasSession_ReceiveContentObject(VegasSession *session, TransportMessage *tm)
+{
+ assertTrue(transportMessage_IsContentObject(tm),
+ "Transport message is not a content object");
+
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug)) {
+ CCNxName *name = vegasSession_GetNameFromTransportMessage(tm);
+ char *nameString = NULL;
+ if (name) {
+ nameString = ccnxName_ToString(name);
+ }
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug, __func__,
+ "Session %p connid %3u receive tm %p: %s",
+ (void *) session,
+ rtaConnection_GetConnectionId(session->parent_connection),
+ (void *) tm,
+ nameString);
+ if (nameString) {
+ parcMemory_Deallocate((void **) &nameString);
+ }
+ }
+
+ CCNxTlvDictionary *contentObjectDictionary = transportMessage_GetDictionary(tm);
+
+ // get segment number
+ uint64_t segnum;
+ int res = vegasSession_GetSegnumFromObject(contentObjectDictionary, &segnum);
+ if (res != 0) {
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Warning)) {
+ CCNxName *name = vegasSession_GetNameFromTransportMessage(tm);
+ char *nameString = NULL;
+ if (name) {
+ nameString = ccnxName_ToString(name);
+ }
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Warning, __func__,
+ "Session %p connid %3u receive tm %p has no segment number: %s",
+ (void *) session,
+ rtaConnection_GetConnectionId(session->parent_connection),
+ (void *) tm,
+ nameString);
+ if (nameString) {
+ parcMemory_Deallocate((void **) &nameString);
+ }
+ }
+
+ // couldn't figure it out
+ transportMessage_Destroy(&tm);
+ return -1;
+ }
+
+ // drop out of order
+ if (segnum < session->starting_segnum) {
+ vegasSession_ReceivedBeforeWindowStart(session, segnum);
+
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug)) {
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug, __func__,
+ "Session %p connid %3u : tm %p received segnum %" PRIu64 " before current head %" PRIu64 "",
+ (void *) session,
+ __func__,
+ rtaConnection_GetConnectionId(session->parent_connection),
+ (void *) tm,
+ segnum,
+ session->starting_segnum);
+ }
+
+ transportMessage_Destroy(&tm);
+ return -1;
+ }
+
+ // Update our idea of the final chunk number. This must be done
+ // before running the algorithm because session->final_segnum is used
+ // to decide if we're done.
+ vegasSession_SetFinalBlockId(session, contentObjectDictionary, segnum);
+
+
+ // now run the algorithm on the received object
+
+ struct fc_window_entry *entry = vegasSession_GetWindowEntry(session, tm, segnum);
+
+ if (rtaLogger_IsLoggable(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug)) {
+ CCNxName *name = vegasSession_GetNameFromTransportMessage(tm);
+ char *nameString = NULL;
+ if (name) {
+ nameString = ccnxName_ToString(name);
+ }
+ rtaLogger_Log(rtaFramework_GetLogger(session->parent_framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Debug, __func__,
+ "Session %p connid %3u receive tm %p segment %" PRIu64 " receive: %s",
+ (void *) session,
+ rtaConnection_GetConnectionId(session->parent_connection),
+ (void *) tm,
+ segnum,
+ nameString);
+ if (nameString) {
+ parcMemory_Deallocate((void **) &nameString);
+ }
+ }
+
+ vegasSession_RunAlgorithmOnReceive(session, entry);
+
+ // forward in-order objects to the user fc
+ if (!rtaConnection_BlockedUp(session->parent_connection)) {
+ vegasSession_ForwardObjectsInOrder(session);
+ }
+
+ vegasSession_SendMoreInterests(session, entry);
+
+ return 0;
+}
+
+unsigned
+vegasSession_GetConnectionId(VegasSession *session)
+{
+ assertNotNull(session, "Parameter session must be non-null");
+ return rtaConnection_GetConnectionId(session->parent_connection);
+}
+
+void
+vegasSession_StateChanged(VegasSession *session)
+{
+ if (rtaConnection_BlockedUp(session->parent_connection)) {
+ // if we're blocked in the up direction, don't do anything. We make this
+ // check every time we're about ti send stuff up the stack in vegasSession_ReceiveContentObject().
+ } else {
+ // unblocked, forward packets
+ vegasSession_ForwardObjectsInOrder(session);
+ }
+
+ if (rtaConnection_BlockedDown(session->parent_connection)) {
+ // stop generating interests
+ } else {
+ // restart interests
+ }
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/vegas_private.h b/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/vegas_private.h
new file mode 100644
index 00000000..b2088567
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/Flowcontrol_Vegas/vegas_private.h
@@ -0,0 +1,222 @@
+/*
+ * 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 vegas_private.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef Libccnx_vegas_private_h
+#define Libccnx_vegas_private_h
+
+#include <ccnx/common/ccnx_Name.h>
+#include <ccnx/common/internal/ccnx_ContentObjectInterface.h>
+
+typedef uint64_t segnum_t;
+
+struct vegas_session;
+typedef struct vegas_session VegasSession;
+
+struct vegas_connection_state;
+typedef struct vegas_connection_state VegasConnectionState;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] fc An allocated Vegas flow controller
+ * @param [in] conn The RTA connection owning the flow
+ * @param [in] basename The name without a chunk number
+ * @param [in] begin The chunk number to begin requesting at
+ * @param [in] interestInterface The {@link CCNxInterestInterface} to use to generate new Interests
+ * @param [in] lifetime The default lifetime, in milli-seconds, to use for generated Interests
+ * @param [in] keyIdRestriction The KeyIdRestriction, if any, from the originating Interest
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+VegasSession *vegasSession_Create(VegasConnectionState *fc, RtaConnection *conn, CCNxName *basename,
+ segnum_t begin, CCNxInterestInterface *interestInterface, uint32_t lifetime,
+ PARCBuffer *keyIdRestriction);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void vegasSession_Destroy(VegasSession **sessionPtr);
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+int vegasSession_Start(VegasSession *session);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+int vegasSession_Pause(VegasSession *session);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+int vegasSession_Resume(VegasSession *session);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+int vegasSession_Seek(VegasSession *session, segnum_t absolutePosition);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+int vegasSession_ReceiveContentObject(VegasSession *session, TransportMessage *tm);
+
+
+/**
+ * Tell a session that there was a state change in its connection
+ *
+ * The caller should ensure that the session's connection is the right one by
+ * using {@link vegasSession_GetConnectionId}.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void vegasSession_StateChanged(VegasSession *session);
+
+/**
+ * Returns the connection id used by the session
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+unsigned vegasSession_GetConnectionId(VegasSession *session);
+
+
+/**
+ * <#One Line Description#>
+ *
+ * Called by a session when it is done
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void vegas_EndSession(VegasConnectionState *fc, VegasSession *session);
+#endif // Libccnx_vegas_private_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/codec_Signing.c b/libccnx-transport-rta/ccnx/transport/transport_rta/components/codec_Signing.c
new file mode 100644
index 00000000..322bea2e
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/codec_Signing.c
@@ -0,0 +1,80 @@
+/*
+ * 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 <parc/algol/parc_Memory.h>
+
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_SymmetricKeySigner.h>
+#include <parc/security/parc_SymmetricKeyStore.h>
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_CryptoHashType.h>
+
+#include <ccnx/transport/transport_rta/config/config_Signer.h>
+#include "codec_Signing.h"
+
+PARCSigner *
+component_Codec_GetSigner(RtaConnection *conn)
+{
+ PARCSigner *signer = NULL;
+
+ SignerType signertype = signer_GetImplementationType(rtaConnection_GetParameters(conn));
+
+ switch (signertype) {
+ case SignerType_SymmetricKeySigner: {
+ struct symmetrickeysigner_params params;
+ bool success = symmetricKeySigner_GetConnectionParams(rtaConnection_GetParameters(conn), &params);
+ assertTrue(success, "Could not retrieve symmetricKeySigner_GetConnectionParams");
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_OpenFile(params.filename, params.password, PARCCryptoHashType_SHA256);
+ PARCSymmetricKeySigner *symmetricKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA256);
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+
+ signer = parcSigner_Create(symmetricKeySigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&symmetricKeySigner);
+ assertNotNull(signer, "got null opening FileKeystore '%s'\n", params.filename);
+ break;
+ }
+
+ case SignerType_PublicKeySigner: {
+ struct publickeysigner_params params;
+ bool success = publicKeySigner_GetConnectionParams(rtaConnection_GetParameters(conn), &params);
+ assertTrue(success, "Could not retrieve publicKeySigner_GetConnectionParams");
+
+ PARCPkcs12KeyStore *pkcs12KeyStore = parcPkcs12KeyStore_Open(params.filename, params.password, PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(pkcs12KeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&pkcs12KeyStore);
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256);
+ parcKeyStore_Release(&keyStore);
+
+ signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+ assertNotNull(signer, "got null opening FileKeystore '%s'\n", params.filename);
+ break;
+ }
+
+ default:
+ assertTrue(0, "Unsupported signer type %d", signertype);
+ }
+
+ assertNotNull(signer, "Did not match a known signer");
+ return signer;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/codec_Signing.h b/libccnx-transport-rta/ccnx/transport/transport_rta/components/codec_Signing.h
new file mode 100644
index 00000000..d46f1ed4
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/codec_Signing.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 codec_Signing.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef Libccnx_codec_Signing_h
+#define Libccnx_codec_Signing_h
+
+#include <parc/security/parc_Signer.h>
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] connection <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCSigner *component_Codec_GetSigner(RtaConnection *connection);
+#endif // Libccnx_codec_Signing_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Codec.h b/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Codec.h
new file mode 100644
index 00000000..8cc15220
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Codec.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.
+ */
+
+/**
+ * @file component_Codec.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef Libccnx_component_codec_h
+#define Libccnx_component_codec_h
+
+// Function structs for component variations. There's only the TLV codec now.
+extern RtaComponentOperations codec_tlv_ops;
+#endif // Libccnx_component_codec_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Codec_Tlv.c b/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Codec_Tlv.c
new file mode 100644
index 00000000..8f90cb06
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Codec_Tlv.c
@@ -0,0 +1,319 @@
+/*
+ * 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 <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/socket.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <ccnx/transport/common/transport_Message.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Framework_Services.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvPacket.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h>
+
+#include "component_Codec.h"
+#include "codec_Signing.h"
+
+// set to 3 or higher for memory dumps of packets
+#ifndef DEBUG_OUTPUT
+#define DEBUG_OUTPUT 0
+#endif
+
+static int component_Codec_Tlv_Init(RtaProtocolStack *stack);
+static int component_Codec_Tlv_Opener(RtaConnection *conn);
+static void component_Codec_Tlv_Upcall_Read(PARCEventQueue *, PARCEventType event, void *conn);
+static void component_Codec_Tlv_Downcall_Read(PARCEventQueue *, PARCEventType event, void *conn);
+static int component_Codec_Tlv_Closer(RtaConnection *conn);
+static int component_Codec_Tlv_Release(RtaProtocolStack *stack);
+static void component_Codec_Tlv_StateChange(RtaConnection *conn);
+
+RtaComponentOperations codec_tlv_ops = {
+ .init = component_Codec_Tlv_Init,
+ .open = component_Codec_Tlv_Opener,
+ .upcallRead = component_Codec_Tlv_Upcall_Read,
+ .upcallEvent = NULL,
+ .downcallRead = component_Codec_Tlv_Downcall_Read,
+ .downcallEvent = NULL,
+ .close = component_Codec_Tlv_Closer,
+ .release = component_Codec_Tlv_Release,
+ .stateChange = component_Codec_Tlv_StateChange
+};
+
+typedef struct codec_connection_state {
+ PARCSigner *signer;
+} CodecConnectionState;
+
+// ==================
+// NULL
+
+static int
+component_Codec_Tlv_Init(RtaProtocolStack *stack)
+{
+ // no ProtocolStack wide state
+ return 0;
+}
+
+
+static int
+component_Codec_Tlv_Opener(RtaConnection *conn)
+{
+ struct codec_connection_state *codec_state = parcMemory_AllocateAndClear(sizeof(struct codec_connection_state));
+ assertNotNull(codec_state, "%s parcMemory_AllocateAndClear(%zu) returned NULL", __func__, sizeof(struct codec_connection_state));
+
+ codec_state->signer = component_Codec_GetSigner(conn);
+
+ rtaConnection_SetPrivateData(conn, CODEC_TLV, codec_state);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s connection %u codec signer %p private %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ rtaConnection_GetConnectionId(conn),
+ (void *) codec_state->signer,
+ (void *) codec_state);
+ }
+
+ return 0;
+}
+
+static void
+upcallDictionary(TransportMessage *tm, PARCEventQueue *out, RtaComponentStats *stats)
+{
+ CCNxTlvDictionary *dictionary = transportMessage_GetDictionary(tm);
+
+ PARCBuffer *wireFormat = ccnxWireFormatMessage_GetWireFormatBuffer(dictionary);
+ bool success = ccnxCodecTlvPacket_BufferDecode(wireFormat, dictionary);
+
+ if (success) {
+ if (rtaComponent_PutMessage(out, tm)) {
+ rtaComponentStats_Increment(stats, STATS_UPCALL_OUT);
+ }
+ } else {
+ printf("Decoding error!");
+ parcBuffer_Display(wireFormat, 3);
+ }
+}
+
+/* Read from below and send to above */
+static void
+component_Codec_Tlv_Upcall_Read(PARCEventQueue *in, PARCEventType event, void *ptr)
+{
+ RtaProtocolStack *stack = (RtaProtocolStack *) ptr;
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(stack, CODEC_TLV, RTA_UP);
+ TransportMessage *tm;
+
+ while ((tm = rtaComponent_GetMessage(in)) != NULL) {
+ RtaConnection *conn = rtaConnection_GetFromTransport(tm);
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, CODEC_TLV);
+ rtaComponentStats_Increment(stats, STATS_UPCALL_IN);
+
+ if (transportMessage_IsControl(tm)) {
+ if (rtaComponent_PutMessage(out, tm)) {
+ rtaComponentStats_Increment(stats, STATS_UPCALL_OUT);
+ }
+ } else {
+ upcallDictionary(tm, out, stats);
+ }
+
+ if (DEBUG_OUTPUT) {
+ struct timeval delay = transportMessage_GetDelay(tm);
+ printf("%9" PRIu64 " %s total upcall reads in %" PRIu64 " out %" PRIu64 " last delay %.6f\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ rtaComponentStats_Get(stats, STATS_UPCALL_IN),
+ rtaComponentStats_Get(stats, STATS_UPCALL_OUT),
+ delay.tv_sec + delay.tv_usec * 1E-6);
+ }
+ }
+}
+
+
+static TransportMessage *
+component_Codec_Tlv_EncodeDictionary_SchemaV1(TransportMessage *tm, RtaConnection *conn, CCNxTlvDictionary *packetDictionary)
+{
+ bool hasWireFormat = (ccnxTlvDictionary_IsValueIoVec(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat) ||
+ ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat));
+
+ if (!hasWireFormat) {
+ CodecConnectionState *codec_conn_state = rtaConnection_GetPrivateData(conn, CODEC_TLV);
+ assertNotNull(codec_conn_state, "%s got null private data\n", __func__);
+
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(packetDictionary, codec_conn_state->signer);
+
+ if (vec) {
+ // store a reference back into the dictioary
+ bool success = ccnxWireFormatMessage_PutIoVec(packetDictionary, vec);
+ assertTrue(success, "Failed to save wire format in the dictionary")
+ {
+ ccnxCodecNetworkBufferIoVec_Display(vec, 0);
+ }
+
+ if (DEBUG_OUTPUT > 2) {
+ printf("%s encoded packet:\n", __func__);
+ ccnxCodecNetworkBufferIoVec_Display(vec, 0);
+ }
+
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+ } else {
+ trapUnexpectedState("Error encoding packet")
+ {
+ ccnxTlvDictionary_Display(packetDictionary, 0);
+ }
+ }
+ } else {
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s packetDictionary %p already has wire format\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) packetDictionary);
+ }
+ }
+
+ if (tm && DEBUG_OUTPUT > 2) {
+ CCNxCodecNetworkBufferIoVec *vec = ccnxWireFormatMessage_GetIoVec(packetDictionary);
+ printf("%9" PRIu64 " %s packetDictionary %p wire format dump\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) packetDictionary);
+ ccnxCodecNetworkBufferIoVec_Display(vec, 3);
+ }
+
+ return tm;
+}
+
+
+static TransportMessage *
+component_Codec_Tlv_EncodeDictionary(TransportMessage *tm, RtaConnection *conn)
+{
+ // If the dictionary already contains a wireformat, we use that and skip encoding
+ CCNxTlvDictionary *packetDictionary = transportMessage_GetDictionary(tm);
+
+ assertNotNull(packetDictionary, "Got a NULL packet dictionary for dictionary based encoding");
+ if (packetDictionary) {
+ switch (ccnxTlvDictionary_GetSchemaVersion(packetDictionary)) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ return component_Codec_Tlv_EncodeDictionary_SchemaV1(tm, conn, packetDictionary);
+ break;
+
+ default:
+ trapIllegalValue(packetDictionary, "Unknown schema version: %d", ccnxTlvDictionary_GetSchemaVersion(packetDictionary));
+ }
+ }
+ return NULL;
+}
+
+/* Read from above and send to below */
+static void
+component_Codec_Tlv_Downcall_Read(PARCEventQueue *in, PARCEventType event, void *ptr)
+{
+ RtaProtocolStack *stack = (RtaProtocolStack *) ptr;
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(stack, CODEC_TLV, RTA_DOWN);
+ TransportMessage *tm;
+
+
+ while ((tm = rtaComponent_GetMessage(in)) != NULL) {
+ RtaConnection *conn = rtaConnection_GetFromTransport(tm);
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, CODEC_TLV);
+ rtaComponentStats_Increment(stats, STATS_DOWNCALL_IN);
+
+ // this will encode everything, including control messages
+ TransportMessage *encoded = component_Codec_Tlv_EncodeDictionary(tm, conn);
+
+ if (encoded) {
+ if (rtaComponent_PutMessage(out, encoded)) {
+ rtaComponentStats_Increment(stats, STATS_DOWNCALL_OUT);
+ }
+ } else {
+ tm = NULL;
+ }
+
+ if (DEBUG_OUTPUT && tm) {
+ struct timeval delay = transportMessage_GetDelay(tm);
+ printf("%9" PRIu64 " %s total downcall reads in %" PRIu64 " out %" PRIu64 " last delay %.6f\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ rtaComponentStats_Get(stats, STATS_DOWNCALL_IN),
+ rtaComponentStats_Get(stats, STATS_DOWNCALL_OUT),
+ delay.tv_sec + delay.tv_usec * 1E-6);
+ }
+ }
+}
+
+static int
+component_Codec_Tlv_Closer(RtaConnection *conn)
+{
+ struct codec_connection_state *codec_conn_state;
+
+ codec_conn_state = rtaConnection_GetPrivateData(conn, CODEC_TLV);
+ assertNotNull(codec_conn_state, "%s got null private data\n", __func__);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s connection %u codec signer %p private %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ rtaConnection_GetConnectionId(conn),
+ (void *) codec_conn_state->signer,
+ (void *) codec_conn_state);
+ }
+
+ parcSigner_Release(&codec_conn_state->signer);
+
+ parcMemory_Deallocate((void **) &codec_conn_state);
+
+ return 0;
+}
+
+static int
+component_Codec_Tlv_Release(RtaProtocolStack *stack)
+{
+ // no ProtocolStack wide state
+ return 0;
+}
+
+static void
+component_Codec_Tlv_StateChange(RtaConnection *conn)
+{
+ struct codec_connection_state *codec_conn_state;
+
+ codec_conn_state = rtaConnection_GetPrivateData(conn, CODEC_TLV);
+ assertNotNull(codec_conn_state, "%s got null private data\n", __func__);
+
+ if (DEBUG_OUTPUT) {
+ printf("%s connection %p codec signer %p private %p\n",
+ __func__,
+ (void *) conn,
+ (void *) codec_conn_state->signer,
+ (void *) codec_conn_state);
+ }
+}
+
+// ==================
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Flowcontrol.h b/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Flowcontrol.h
new file mode 100644
index 00000000..6a3bcb44
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Flowcontrol.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.
+ */
+
+//
+// component_Flowcontrol.h
+// Libccnx
+//
+//
+//
+
+#ifndef Libccnx_component_flow_h
+#define Libccnx_component_flow_h
+
+// Function structs for component variations
+extern RtaComponentOperations flow_vegas_ops;
+extern RtaComponentOperations flow_null_ops;
+#endif // Libccnx_component_flow_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Testing.c b/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Testing.c
new file mode 100644
index 00000000..51a71285
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Testing.c
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+/**
+ * the Testing component does not implement any of its methods. This means it may be inserted above and
+ * below another component so a unit test can look at its queues
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include <LongBow/runtime.h>
+
+#include <ccnx/transport/transport_rta/rta_Transport.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+
+#include <ccnx/transport/transport_rta/components/component_Testing.h>
+
+RtaComponentOperations testing_null_ops = {
+ .init = NULL, /* init */
+ .open = NULL, /* open */
+ .upcallRead = NULL, /* upcall read */
+ .upcallEvent = NULL,
+ .downcallRead = NULL, /* downcall read */
+ .downcallEvent = NULL,
+ .close = NULL, /* closer */
+ .release = NULL /* release */
+};
+
+// ==================
+// NULL
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Testing.h b/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Testing.h
new file mode 100644
index 00000000..4cec0ff2
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/component_Testing.h
@@ -0,0 +1,41 @@
+/*
+ * 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 component_Testing.h
+ * @brief A component that takes no actions, not even reads.
+ *
+ * This is useful to put in the stack around a component under test to
+ * isolate it from the system and then intercept the queues.
+ *
+ * This component may be used as both TESTING_UPPER and TESTING_LOWER
+ * to surround another component:
+ *
+ * { SYSTEM : COMPONENTS : [TESTING_UPPER, component under test, TESTING_LOWER] }
+ *
+ * In your test code, you would then have something like this to operate in
+ * the "down" direction:
+ * PARCEventQueue *upper = rtaProtocolStack_GetPutQueue(stack, TESTING_UPPER, RTA_DOWN);
+ * PARCEventQueue *rea = rtaProtocolStack_GetPutQueue(stack, component under test, RTA_UP);
+ * PARCEventQueue *lower = rtaProtocolStack_GetPutQueue(stack, TESTING_LOWER, RTA_UP);
+ *
+ */
+#ifndef Libccnx_component_Testing_h
+#define Libccnx_component_Testing_h
+
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+
+extern RtaComponentOperations testing_null_ops;
+#endif // Libccnx_component_Testing_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/CMakeLists.txt b/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/CMakeLists.txt
new file mode 100644
index 00000000..0b4416f7
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/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_codec_Signing
+ test_component_Codec_Tlv
+ test_component_Codec_Tlv_Hmac
+ test_component_Testing
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_codec_Signing.c b/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_codec_Signing.c
new file mode 100644
index 00000000..3740994b
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_codec_Signing.c
@@ -0,0 +1,61 @@
+/*
+ * 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 "../codec_Signing.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(codec_Signing)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(codec_Signing)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(codec_Signing)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(codec_Signing);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_component_Codec_Tlv.c b/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_component_Codec_Tlv.c
new file mode 100644
index 00000000..1990d8ae
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_component_Codec_Tlv.c
@@ -0,0 +1,276 @@
+/*
+ * 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 "../component_Codec_Tlv.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <ccnx/api/control/cpi_ControlFacade.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_Security.h>
+#include <ccnx/transport/transport_rta/config/config_All.h>
+
+#include <ccnx/transport/test_tools/traffic_tools.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h>
+#include <ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h>
+
+
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+
+#include "testrig_MockFramework.c"
+
+typedef struct test_data {
+ MockFramework *mock;
+ char keystore_filename[MAXPATH];
+ char keystore_password[MAXPATH];
+} TestData;
+
+static CCNxTransportConfig *
+codecTlv_CreateParams(const char *keystore_filename, const char *keystore_password)
+{
+ assertNotNull(keystore_filename, "Got null keystore name\n");
+ assertNotNull(keystore_password, "Got null keystore passwd\n");
+
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+
+ apiConnector_ProtocolStackConfig(stackConfig);
+ testingUpper_ProtocolStackConfig(stackConfig);
+ tlvCodec_ProtocolStackConfig(stackConfig);
+ testingLower_ProtocolStackConfig(stackConfig);
+ protocolStack_ComponentsConfigArgs(stackConfig, apiConnector_GetName(), testingUpper_GetName(), tlvCodec_GetName(), testingLower_GetName(), NULL);
+
+ CCNxConnectionConfig *connConfig = apiConnector_ConnectionConfig(ccnxConnectionConfig_Create());
+ testingUpper_ConnectionConfig(connConfig);
+ tlvCodec_ConnectionConfig(connConfig);
+ testingLower_ConnectionConfig(connConfig);
+
+ unlink(keystore_filename);
+
+ bool success = parcPkcs12KeyStore_CreateFile(keystore_filename, keystore_password, "alice", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile() failed.");
+
+ publicKeySigner_ConnectionConfig(connConfig, keystore_filename, keystore_password);
+
+ CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig);
+ ccnxStackConfig_Release(&stackConfig);
+ return result;
+}
+
+static TestData *
+_commonSetup(void)
+{
+ parcSecurity_Init();
+
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ sprintf(data->keystore_filename, "/tmp/alice_keystore.p12.XXXXXX");
+ mktemp(data->keystore_filename);
+ sprintf(data->keystore_password, "12345");
+
+ CCNxTransportConfig *config = codecTlv_CreateParams(data->keystore_filename, data->keystore_password);
+ data->mock = mockFramework_Create(config);
+ ccnxTransportConfig_Destroy(&config);
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ mockFramework_Destroy(&data->mock);
+ unlink(data->keystore_filename);
+ parcMemory_Deallocate((void **) &data);
+
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_RUNNER(component_Codec_Tlv)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Dictionary);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(component_Codec_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(component_Codec_Tlv)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ==================================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
+
+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;
+}
+
+// ==================================================================================
+
+static TransportMessage *
+sendDown(TestData *data, TransportMessage *tm_going_down)
+{
+ PARCEventQueue *in = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_LOWER, RTA_UP);
+
+ rtaComponent_PutMessage(in, tm_going_down);
+ // turn the handle enough times, the message will pass all the way out the bottom
+ rtaFramework_NonThreadedStepCount(data->mock->framework, 10);
+ return rtaComponent_GetMessage(out);
+}
+
+static TransportMessage *
+sendUp(TestData *data, TransportMessage *tm_going_down)
+{
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
+ PARCEventQueue *in = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_LOWER, RTA_UP);
+
+ rtaComponent_PutMessage(in, tm_going_down);
+ // turn the handle enough times, the message will pass all the way out the bottom
+ rtaFramework_NonThreadedStepCount(data->mock->framework, 10);
+ return rtaComponent_GetMessage(out);
+}
+
+
+// ==================================================================================
+
+LONGBOW_TEST_FIXTURE(Dictionary)
+{
+ LONGBOW_RUN_TEST_CASE(Dictionary, component_Codec_Tlv_Downcall_Read_Interest);
+ LONGBOW_RUN_TEST_CASE(Dictionary, component_Codec_Tlv_Downcall_Read_Control);
+ LONGBOW_RUN_TEST_CASE(Dictionary, component_Codec_Tlv_Downcall_Read_Raw);
+
+ LONGBOW_RUN_TEST_CASE(Dictionary, component_Codec_Tlv_Upcall_Read_Control);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Dictionary)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Dictionary)
+{
+ _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;
+}
+
+/**
+ * Makes sure an interest going down the stack gets encoded. Does not test
+ * the actual wire format -- that's the job of the tlv unit tests.
+ */
+LONGBOW_TEST_CASE(Dictionary, component_Codec_Tlv_Downcall_Read_Interest)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ TransportMessage *tm = trafficTools_CreateTransportMessageWithDictionaryInterest(data->mock->connection, CCNxTlvDictionary_SchemaVersion_V1);
+ TransportMessage *test_tm = sendDown(data, tm);
+ CCNxCodecNetworkBufferIoVec *vec =
+ ccnxTlvDictionary_GetIoVec(transportMessage_GetDictionary(test_tm), CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat);
+ assertNotNull(vec, "Output of coded did not have a raw format message");
+ transportMessage_Destroy(&test_tm);
+}
+
+/**
+ * control message should be passed through
+ */
+LONGBOW_TEST_CASE(Dictionary, component_Codec_Tlv_Downcall_Read_Control)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ TransportMessage *tm = trafficTools_CreateTransportMessageWithDictionaryControl(data->mock->connection,
+ CCNxTlvDictionary_SchemaVersion_V1);
+ TransportMessage *test_tm = sendDown(data, tm);
+ PARCJSON *json = ccnxControlFacade_GetJson(transportMessage_GetDictionary(test_tm));
+ assertNotNull(json, "Output of codec did not have a control message");
+ transportMessage_Destroy(&test_tm);
+}
+
+LONGBOW_TEST_CASE(Dictionary, component_Codec_Tlv_Downcall_Read_Raw)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ TransportMessage *tm = trafficTools_CreateTransportMessageWithDictionaryRaw(data->mock->connection,
+ CCNxTlvDictionary_SchemaVersion_V1);
+ TransportMessage *test_tm = sendDown(data, tm);
+ PARCBuffer *buffer = ccnxWireFormatMessage_GetWireFormatBuffer(transportMessage_GetDictionary(test_tm));
+ assertNotNull(buffer, "Output of codec did not have a raw format message");
+ transportMessage_Destroy(&test_tm);
+}
+
+LONGBOW_TEST_CASE(Dictionary, component_Codec_Tlv_Upcall_Read_Control)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCBuffer *wireFormat = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c),
+ 0, sizeof(v1_cpi_add_route_crc32c));
+ CCNxTlvDictionary *dictionary = ccnxWireFormatMessage_FromControlPacketType(CCNxTlvDictionary_SchemaVersion_V1, wireFormat);
+ parcBuffer_Release(&wireFormat);
+
+ // We have not set the message type or schema
+ TransportMessage *tm = transportMessage_CreateFromDictionary(dictionary);
+ transportMessage_SetInfo(tm, data->mock->connection, NULL);
+ ccnxTlvDictionary_Release(&dictionary);
+
+ // ------
+ // Now do the actual test of sending the transport message up the stack
+
+ TransportMessage *test_tm = sendUp(data, tm);
+
+ // It should now be parsed into an control message
+ CCNxTlvDictionary *testdict = transportMessage_GetDictionary(test_tm);
+ assertNotNull(testdict, "Failed to get dictionary from the transport message");
+
+ assertTrue(ccnxTlvDictionary_IsControl(testdict), "Dictionary says it is not a Control");
+ assertTrue(ccnxTlvDictionary_GetSchemaVersion(testdict) == CCNxTlvDictionary_SchemaVersion_V1,
+ "Wrong schema, got %d expected %d",
+ ccnxTlvDictionary_GetSchemaVersion(testdict), CCNxTlvDictionary_SchemaVersion_V1);
+
+ transportMessage_Destroy(&tm);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(component_Codec_Tlv);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_component_Codec_Tlv_Hmac.c b/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_component_Codec_Tlv_Hmac.c
new file mode 100644
index 00000000..4934a266
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_component_Codec_Tlv_Hmac.c
@@ -0,0 +1,204 @@
+/*
+ * 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 "../component_Codec_Tlv.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <stdio.h>
+#include <sys/un.h>
+#include <strings.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/runtime.h>
+
+#define DEBUG_OUTPUT 0
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_SymmetricKeyStore.h>
+
+#include <ccnx/transport/transport_rta/config/config_All.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+
+#include <ccnx/transport/test_tools/traffic_tools.h>
+
+#include "testrig_MockFramework.c"
+
+#ifndef MAXPATH
+#define MAXPATH 1024
+#endif
+
+typedef struct test_data {
+ MockFramework *mock;
+ char keystore_filename[MAXPATH];
+ char keystore_password[MAXPATH];
+} TestData;
+
+LONGBOW_TEST_RUNNER(System)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Component_Codec_Tlv_Hmac);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(System)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(System)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ================================
+
+static CCNxTransportConfig *
+codecTlv_CreateParams(const char *keystore_name, const char *keystore_passwd)
+{
+ assertNotNull(keystore_name, "Got null keystore name\n");
+ assertNotNull(keystore_passwd, "Got null keystore passwd\n");
+
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+
+ apiConnector_ProtocolStackConfig(stackConfig);
+ testingUpper_ProtocolStackConfig(stackConfig);
+ tlvCodec_ProtocolStackConfig(stackConfig);
+ testingLower_ProtocolStackConfig(stackConfig);
+ protocolStack_ComponentsConfigArgs(stackConfig,
+ apiConnector_GetName(),
+ testingUpper_GetName(),
+ tlvCodec_GetName(),
+ testingLower_GetName(),
+ NULL);
+
+ CCNxConnectionConfig *connConfig = apiConnector_ConnectionConfig(ccnxConnectionConfig_Create());
+ testingUpper_ConnectionConfig(connConfig);
+ tlvCodec_ConnectionConfig(connConfig);
+ testingLower_ConnectionConfig(connConfig);
+
+ symmetricKeySigner_ConnectionConfig(connConfig, keystore_name, keystore_passwd);
+ CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig);
+ ccnxStackConfig_Release(&stackConfig);
+ return result;
+}
+
+static TestData *
+_commonSetup(void)
+{
+ parcSecurity_Init();
+
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ sprintf(data->keystore_filename, "/tmp/alice_keystore.p12.XXXXXX");
+ mktemp(data->keystore_filename);
+ sprintf(data->keystore_password, "12345");
+
+ unlink(data->keystore_filename);
+ PARCBuffer *secret_key = parcSymmetricKeyStore_CreateKey(256);
+ parcSymmetricKeyStore_CreateFile(data->keystore_filename, data->keystore_password, secret_key);
+ parcBuffer_Release(&secret_key);
+
+ CCNxTransportConfig *config = codecTlv_CreateParams(data->keystore_filename, data->keystore_password);
+ data->mock = mockFramework_Create(config);
+ ccnxTransportConfig_Destroy(&config);
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ mockFramework_Destroy(&data->mock);
+ unlink(data->keystore_filename);
+ parcMemory_Deallocate((void **) &data);
+
+ parcSecurity_Fini();
+}
+
+// ======================================
+
+
+LONGBOW_TEST_FIXTURE(Component_Codec_Tlv_Hmac)
+{
+ LONGBOW_RUN_TEST_CASE(Component_Codec_Tlv_Hmac, open_close);
+ LONGBOW_RUN_TEST_CASE(Component_Codec_Tlv_Hmac, Component_Codec_Tlv_Hmac_Downcall_Read);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Component_Codec_Tlv_Hmac)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Component_Codec_Tlv_Hmac)
+{
+ _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(Component_Codec_Tlv_Hmac, open_close)
+{
+ // dont actually do anything. make sure no memory leaks in setup and teardown.
+}
+
+// ============================================
+// TLV tests
+
+static TransportMessage *
+sendDown(TestData *data, TransportMessage *tm_going_down)
+{
+ PARCEventQueue *in = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_LOWER, RTA_UP);
+
+ rtaComponent_PutMessage(in, tm_going_down);
+ // turn the handle enough times, the message will pass all the way out the bottom
+ rtaFramework_NonThreadedStepCount(data->mock->framework, 5);
+ return rtaComponent_GetMessage(out);
+}
+
+LONGBOW_TEST_CASE(Component_Codec_Tlv_Hmac, Component_Codec_Tlv_Hmac_Downcall_Read)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ TransportMessage *tm = trafficTools_CreateTransportMessageWithSignedContentObject(data->mock->connection);
+
+ TransportMessage *test_tm = sendDown(data, tm);
+
+ // we should now have a RawFormat message
+ CCNxCodecNetworkBufferIoVec *vec = ccnxWireFormatMessage_GetIoVec(transportMessage_GetDictionary(test_tm));
+ assertNotNull(vec, "Output of coded message did not have a raw format message")
+ {
+ ccnxTlvDictionary_Display(transportMessage_GetDictionary(test_tm), 0);
+ }
+
+ transportMessage_Destroy(&test_tm);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(System);
+ exit(longBowMain(argc, argv, testRunner, NULL));
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_component_Testing.c b/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_component_Testing.c
new file mode 100644
index 00000000..6593972f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/test_component_Testing.c
@@ -0,0 +1,82 @@
+/*
+ * 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 "../component_Testing.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(component_Testing)
+{
+ // 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(component_Testing)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(component_Testing)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+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(component_Testing);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/testrig_MockFramework.c b/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/testrig_MockFramework.c
new file mode 100644
index 00000000..0ca07ab1
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/components/test/testrig_MockFramework.c
@@ -0,0 +1,99 @@
+/*
+ * 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 a mock RTA Framework for testing Components and Connectors.
+ *
+ *
+ */
+
+#include <ccnx/transport/transport_rta/core/rta_Framework.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_Commands.c>
+#include <ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.h>
+
+#ifndef MAXPATH
+#define MAXPATH 1024
+#endif
+
+typedef struct mock_framework {
+ PARCRingBuffer1x1*commandRingBuffer;
+ PARCNotifier *commandNotifier;
+ RtaFramework *framework;
+
+ int stackId;
+ RtaProtocolStack *stack;
+
+ int connection_fds[2];
+ RtaConnection *connection;
+
+ CCNxTransportConfig *transport_config;
+} MockFramework;
+
+static MockFramework *
+mockFramework_Create(CCNxTransportConfig *config)
+{
+ MockFramework *mock = parcMemory_AllocateAndClear(sizeof(MockFramework));
+ assertNotNull(mock, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(MockFramework));
+
+ mock->transport_config = ccnxTransportConfig_Copy(config);
+ assertNotNull(mock->transport_config, "%s got null params from createParams\n", __func__);
+
+ mock->commandRingBuffer = parcRingBuffer1x1_Create(128, NULL);
+ mock->commandNotifier = parcNotifier_Create();
+ mock->framework = rtaFramework_Create(mock->commandRingBuffer, mock->commandNotifier);
+
+ // Create the protocol stack
+
+ mock->stackId = 1;
+ RtaCommandCreateProtocolStack *createStack =
+ rtaCommandCreateProtocolStack_Create(mock->stackId, ccnxTransportConfig_GetStackConfig(mock->transport_config));
+ _rtaFramework_ExecuteCreateStack(mock->framework, createStack);
+ rtaCommandCreateProtocolStack_Release(&createStack);
+
+ // peek inside and get the protocol stack reference
+ FrameworkProtocolHolder *fph = rtaFramework_GetProtocolStackByStackId(mock->framework, mock->stackId);
+ mock->stack = fph->stack;
+
+ int error = socketpair(AF_UNIX, SOCK_STREAM, 0, mock->connection_fds);
+ assertFalse(error, "Error creating socket pair: (%d) %s", errno, strerror(errno));
+
+ RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(mock->stackId, mock->connection_fds[0], mock->connection_fds[1],
+ ccnxConnectionConfig_GetJson(ccnxTransportConfig_GetConnectionConfig(mock->transport_config)));
+ _rtaFramework_ExecuteOpenConnection(mock->framework, openConnection);
+ rtaCommandOpenConnection_Release(&openConnection);
+
+ mock->connection = rtaConnectionTable_GetByApiFd(mock->framework->connectionTable, mock->connection_fds[0]);
+
+ // Uses the non-threaded forwarder, make sure we step at least once
+ rtaFramework_NonThreadedStep(mock->framework);
+
+ return mock;
+}
+
+static void
+mockFramework_Destroy(MockFramework **mockPtr)
+{
+ MockFramework *mock = *mockPtr;
+
+ rtaFramework_Teardown(mock->framework);
+
+ parcRingBuffer1x1_Release(&mock->commandRingBuffer);
+ parcNotifier_Release(&mock->commandNotifier);
+
+ rtaFramework_Destroy(&mock->framework);
+ ccnxTransportConfig_Destroy(&mock->transport_config);
+
+ parcMemory_Deallocate((void **) &mock);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_All.h b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_All.h
new file mode 100644
index 00000000..54d068fe
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_All.h
@@ -0,0 +1,45 @@
+/*
+ * 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 a convenience header for an API that wishes to import all the standard
+ * component configuration headers.
+ */
+
+#ifndef Libccnx_config_all_h
+#define Libccnx_config_all_h
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+#include <ccnx/transport/transport_rta/config/config_ApiConnector.h>
+
+#include <ccnx/transport/transport_rta/config/config_Codec_Tlv.h>
+#include <ccnx/transport/transport_rta/config/config_CryptoCache.h>
+
+#include <ccnx/transport/transport_rta/config/config_FlowControl_Vegas.h>
+#include <ccnx/transport/transport_rta/config/config_Forwarder_Local.h>
+#include <ccnx/transport/transport_rta/config/config_Forwarder_Metis.h>
+
+#include <ccnx/transport/transport_rta/config/config_InMemoryVerifier.h>
+
+#include <ccnx/transport/transport_rta/config/config_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/config/config_PublicKeySigner.h>
+
+#include <ccnx/transport/transport_rta/config/config_Signer.h>
+#include <ccnx/transport/transport_rta/config/config_SymmetricKeySigner.h>
+
+#include <ccnx/transport/transport_rta/config/config_TestingComponent.h>
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ApiConnector.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ApiConnector.c
new file mode 100644
index 00000000..6af665bb
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ApiConnector.c
@@ -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.
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include "config_ApiConnector.h"
+
+#include <ccnx/transport/transport_rta/core/components.h>
+
+/**
+ * Generates:
+ *
+ * { "API_CONNECTOR" : { } }
+ */
+CCNxStackConfig *
+apiConnector_ProtocolStackConfig(CCNxStackConfig *stackConfig)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ CCNxStackConfig *result = ccnxStackConfig_Add(stackConfig, apiConnector_GetName(), value);
+ parcJSONValue_Release(&value);
+
+ return result;
+}
+
+CCNxConnectionConfig *
+apiConnector_ConnectionConfig(CCNxConnectionConfig *connectionConfig)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ CCNxConnectionConfig *result = ccnxConnectionConfig_Add(connectionConfig, apiConnector_GetName(), value);
+ parcJSONValue_Release(&value);
+
+ return result;
+}
+
+const char *
+apiConnector_GetName(void)
+{
+ return RtaComponentNames[API_CONNECTOR];
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ApiConnector.h b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ApiConnector.h
new file mode 100644
index 00000000..7e0867ad
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ApiConnector.h
@@ -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.
+ */
+
+/**
+ * @file config_ApiConnector.h
+ * @brief Generates stack and connection configuration information
+ *
+ * Each component in the protocol stack must have a configuration element.
+ * This module generates the configuration elements for the API Connector.
+ *
+ * @code
+ * {
+ * // Configure a stack with {APIConnector,TLVCodec,MetisConnector}
+ *
+ * CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+ * CCNxConnectionConfig *connConfig = ccnxConnectionConfig_Create();
+ *
+ * apiConnector_ProtocolStackConfig(stackConfig);
+ * apiConnector_ConnectionConfig(connConfig);
+ * tlvCodec_ProtocolStackConfig(stackConfig);
+ * tlvCodec_ConnectionConfig(connConfig);
+ * metisForwarder_ProtocolStackConfig(stackConfig);
+ * metisForwarder_ConnectionConfig(connConfig, metisForwarder_GetDefaultPort());
+ *
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connConfig);
+ * }
+ *
+ */
+#ifndef Libccnx_config_ApiConnector_h
+#define Libccnx_config_ApiConnector_h
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+/**
+ * Generates the configuration settings included in the Protocol Stack configuration
+ *
+ * Adds configuration elements to the Protocol Stack configuration
+ * { "API_CONNECTOR" : { } }
+ *
+ * @param [in] stackConfig The protocl stack configuration to update
+ *
+ * @return non-null The updated protocol stack configuration
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxStackConfig *apiConnector_ProtocolStackConfig(CCNxStackConfig *stackConfig);
+
+/**
+ * Generates the configuration settings included in the Connection configuration
+ *
+ * Adds configuration elements to the `CCNxConnectionConfig`
+ *
+ * @param [in] config A pointer to a valid CCNxConnectionConfig instance.
+ *
+ * @return non-null The modified `CCNxConnectionConfig`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxConnectionConfig *apiConnector_ConnectionConfig(CCNxConnectionConfig *config);
+
+/**
+ * Returns the text string for this component
+ *
+ * Used as the text key to a JSON block. You do not need to free it.
+ *
+ * @return non-null A text string unique to this component
+ *
+ */
+const char *apiConnector_GetName(void);
+#endif
+
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Codec_Ccnb.xc b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Codec_Ccnb.xc
new file mode 100644
index 00000000..04820d6e
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Codec_Ccnb.xc
@@ -0,0 +1,31 @@
+
+#include <config.h>
+#include <stdio.h>
+#include "config_Codec_Ccnb.h"
+
+#include "components.h"
+
+/**
+ * Generates:
+
+ { "CCNB_CODEC" : { } }
+ */
+ProtocolStackConfig *
+ccnbCodec_ProtocolStackConfig(ProtocolStackConfig *stackConfig)
+{
+ return protocolStackConfig_Add(stackConfig, ccnbCodec_GetName(), parcJSONValue_CreateNULL());//ccnxJson_CreateObject());
+}
+
+ConnectionConfig *
+ccnbCodec_ConnectionConfig(ConnectionConfig *connectionConfig)
+{
+ return connectionConfig_Add(connectionConfig, ccnbCodec_GetName(), parcJSONValue_CreateNULL());//ccnxJson_CreateObject());
+}
+
+
+const char * ccnbCodec_GetName()
+{
+ return RtaComponentNames[CODEC_CCNB];
+
+}
+
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Codec_Tlv.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Codec_Tlv.c
new file mode 100644
index 00000000..b3eeb6a7
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Codec_Tlv.c
@@ -0,0 +1,62 @@
+/*
+ * 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 "config_Codec_Tlv.h"
+#include <LongBow/runtime.h>
+
+#include <ccnx/transport/transport_rta/core/components.h>
+
+//static const char param_SCHEMA[] = "SCHEMA";
+//static const char param_CODEC[] = "CODEC";
+//static const int default_schema = 0;
+
+/**
+ * Generates:
+ *
+ * { "CODEC_TLV" : { } }
+ */
+CCNxStackConfig *
+tlvCodec_ProtocolStackConfig(CCNxStackConfig *stackConfig)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ CCNxStackConfig *result = ccnxStackConfig_Add(stackConfig, tlvCodec_GetName(), value);
+ parcJSONValue_Release(&value);
+
+ return result;
+}
+
+/**
+ * Generates:
+ *
+ * { "CODEC_TLV" : { } }
+ */
+
+CCNxConnectionConfig *
+tlvCodec_ConnectionConfig(CCNxConnectionConfig *connectionConfig)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ CCNxConnectionConfig *result = ccnxConnectionConfig_Add(connectionConfig, tlvCodec_GetName(), value);
+ parcJSONValue_Release(&value);
+ return result;
+}
+
+const char *
+tlvCodec_GetName(void)
+{
+ return RtaComponentNames[CODEC_TLV];
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Codec_Tlv.h b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Codec_Tlv.h
new file mode 100644
index 00000000..213fc1c2
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Codec_Tlv.h
@@ -0,0 +1,92 @@
+/*
+ * 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 config_Codec_Tlv.h
+ * @brief Generates stack and connection configuration information
+ *
+ * Each component in the protocol stack must have a configuration element.
+ * This module generates the configuration elements for the TLV codec.
+ *
+ * @code
+ * {
+ * // Configure a stack with {APIConnector,TLVCodec,MetisConnector}
+ *
+ * stackConfig = ccnxStackConfig_Create();
+ * connConfig = ccnxConnectionConfig_Create();
+ *
+ * apiConnector_ProtocolStackConfig(stackConfig);
+ * apiConnector_ConnectionConfig(connConfig);
+ * tlvCodec_ProtocolStackConfig(stackConfig);
+ * tlvCodec_ConnectionConfig(connConfig);
+ * metisForwarder_ProtocolStackConfig(stackConfig);
+ * metisForwarder_ConnectionConfig(connConfig, metisForwarder_GetDefaultPort());
+ *
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connConfig);
+ * }
+ *
+ */
+
+#ifndef Libccnx_config_Codec_Tlv_h
+#define Libccnx_config_Codec_Tlv_h
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+/**
+ * Generates the configuration settings included in the Protocol Stack configuration
+ *
+ * Adds configuration elements to the Protocol Stack configuration
+ *
+ * { "TLV_CODEC" : { } }
+ *
+ * @param [in] stackConfig The protocl stack configuration to update
+ *
+ * @return non-null The updated protocol stack configuration
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxStackConfig *tlvCodec_ProtocolStackConfig(CCNxStackConfig *stackConfig);
+
+/**
+ * Creates a connection configuration based on CCNxMessages wrapping an CCNxTlvDictionary
+ *
+ * Adds configuration elements to the `CCNxConnectionConfig`
+ *
+ * @param [in] config A pointer to a valid CCNxConnectionConfig instance.
+ *
+ * @return non-null The modified `CCNxConnectionConfig`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxConnectionConfig *tlvCodec_ConnectionConfig(CCNxConnectionConfig *config);
+
+/**
+ * Returns the text string for this component
+ *
+ * Used as the text key to a JSON block. You do not need to free it.
+ *
+ * @return non-null A text string unique to this component
+ *
+ */
+const char *tlvCodec_GetName(void);
+
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_CryptoCache.h b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_CryptoCache.h
new file mode 100644
index 00000000..f707c324
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_CryptoCache.h
@@ -0,0 +1,41 @@
+/*
+ * 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_config_CryptoCache_h
+#define Libccnx_config_CryptoCache_h
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+/**
+ * Generates:
+ *
+ * { "KEYS" :
+ * [
+ * { "KEYID" : base64{ keyhash },
+ * "KEY" : base64{ derEncodedKey },
+ * "PREFIXES" : [ uripath, uripath, ... uripath ]
+ * },
+ * { "KEYID" : base64{ keyhash },
+ * "KEY" : base64{ derEncodedKey },
+ * "PREFIXES" : [ uripath, uripath, ... uripath ]
+ * },
+ * ...
+ * ]
+ * }
+ */
+CCNxConnectionConfig *cryptoCache_ConnectionConfig(CCNxConnectionConfig *connConfig, const char *filename, const char *password);
+
+const char *cryptoCache_GetName(void);
+#endif // Libccnx_config_CryptoCache_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_FlowControl_Vegas.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_FlowControl_Vegas.c
new file mode 100644
index 00000000..9b31d26e
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_FlowControl_Vegas.c
@@ -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.
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+#include "config_FlowControl_Vegas.h"
+
+#include <ccnx/transport/transport_rta/core/components.h>
+
+/**
+ * Generates:
+ *
+ * { "FC_VEGAS" : { } }
+ */
+CCNxStackConfig *
+vegasFlowController_ProtocolStackConfig(CCNxStackConfig *stackConfig)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ CCNxStackConfig *result = ccnxStackConfig_Add(stackConfig, vegasFlowController_GetName(), value);
+ parcJSONValue_Release(&value);
+ return result;
+}
+
+CCNxConnectionConfig *
+vegasFlowController_ConnectionConfig(CCNxConnectionConfig *connectionConfig)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ CCNxConnectionConfig *result = ccnxConnectionConfig_Add(connectionConfig, vegasFlowController_GetName(), value);
+ parcJSONValue_Release(&value);
+ return result;
+}
+
+const char *
+vegasFlowController_GetName(void)
+{
+ return RtaComponentNames[FC_VEGAS];
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_FlowControl_Vegas.h b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_FlowControl_Vegas.h
new file mode 100644
index 00000000..28bcd992
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_FlowControl_Vegas.h
@@ -0,0 +1,92 @@
+/*
+ * 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 config_FlowControl_Vegas.h
+ * @brief Generates stack and connection configuration information
+ *
+ * Each component in the protocol stack must have a configuration element.
+ * This module generates the configuration elements for the API Connector.
+ *
+ * @code
+ * {
+ * // Configure a stack with {APIConnector,Vegas,TLVCodec,MetisConnector}
+ *
+ * stackConfig = ccnxStackConfig_Create();
+ * connConfig = ccnxConnectionConfig_Create();
+ *
+ * apiConnector_ProtocolStackConfig(stackConfig);
+ * apiConnector_ConnectionConfig(connConfig);
+ * vegasFlowController_ProtocolStackConfig(stackConfig);
+ * vegasFlowController_ConnectionConfig(connConfig);
+ * tlvCodec_ProtocolStackConfig(stackConfig);
+ * tlvCodec_ConnectionConfig(connConfig);
+ * metisForwarder_ProtocolStackConfig(stackConfig);
+ * metisForwarder_ConnectionConfig(connConfig, metisForwarder_GetDefaultPort());
+ *
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connConfig);
+ * }
+ *
+ */
+
+#ifndef Libccnx_config_FlowControl_Vegas_h
+#define Libccnx_config_FlowControl_Vegas_h
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+/**
+ * Generates the configuration settings included in the Protocol Stack configuration
+ *
+ * Adds configuration elements to the Protocol Stack configuration
+ *
+ * { "FC_VEGAS" : { } }
+ *
+ * @param [in] stackConfig The protocl stack configuration to update
+ *
+ * @return non-null The updated protocol stack configuration
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxStackConfig *vegasFlowController_ProtocolStackConfig(CCNxStackConfig *stackConfig);
+
+/**
+ * Generates the configuration settings included in the Connection configuration
+ *
+ * Adds configuration elements to the `CCNxConnectionConfig`
+ *
+ * @param [in] config The CCNxConnectionConfig instance
+ *
+ * @return non-null The modified `CCNxConnectionConfig`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxConnectionConfig *vegasFlowController_ConnectionConfig(CCNxConnectionConfig *config);
+
+/**
+ * Returns the text string for this component
+ *
+ * Used as the text key to a JSON block. You do not need to free it.
+ *
+ * @return non-null A text string unique to this component
+ *
+ */
+const char *vegasFlowController_GetName(void);
+#endif // Libccnx_config_FlowControl_Vegas_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Local.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Local.c
new file mode 100644
index 00000000..d5c94854
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Local.c
@@ -0,0 +1,72 @@
+/*
+ * 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 "config_Forwarder_Local.h"
+
+#include <ccnx/transport/transport_rta/core/components.h>
+#include <LongBow/runtime.h>
+
+static const char param_FWD_LOCAL_NAME[] = "LOCAL_NAME";
+
+CCNxStackConfig *
+localForwarder_ProtocolStackConfig(CCNxStackConfig *stackConfig)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ CCNxStackConfig *result = ccnxStackConfig_Add(stackConfig, localForwarder_GetName(), value);
+ parcJSONValue_Release(&value);
+ return result;
+}
+
+/**
+ * Generates:
+ *
+ * { "FWD_LOCAL" : { "path" : pipePath } }
+ */
+CCNxConnectionConfig *
+localForwarder_ConnectionConfig(CCNxConnectionConfig *connConfig, const char *pipePath)
+{
+ PARCJSON *json = parcJSON_Create();
+ parcJSON_AddString(json, param_FWD_LOCAL_NAME, pipePath);
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ parcJSON_Release(&json);
+ CCNxConnectionConfig *result = ccnxConnectionConfig_Add(connConfig, localForwarder_GetName(), value);
+ parcJSONValue_Release(&value);
+ return result;
+}
+
+const char *
+localForwarder_GetName()
+{
+ return RtaComponentNames[FWD_LOCAL];
+}
+
+const char *
+localForwarder_GetPath(PARCJSON *json)
+{
+ PARCJSONValue *value = parcJSON_GetValueByName(json, localForwarder_GetName());
+ assertNotNull(value, "Got null for %s json", localForwarder_GetName());
+ PARCJSON *localJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(localJson, param_FWD_LOCAL_NAME);
+ assertNotNull(value, "Must specify a path for the PF_UNIX pipe for local forwarder");
+ assertTrue(parcJSONValue_IsString(value), "JSON key %s must be type STRING", localForwarder_GetName());
+
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ const char *path = parcBuffer_Overlay(sBuf, 0);
+
+ return path;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Local.h b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Local.h
new file mode 100644
index 00000000..6b865aa8
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Local.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 config_Forwarder_Local.h
+ * @brief Generates stack and connection configuration information
+ *
+ * Each component in the protocol stack must have a configuration element.
+ * This module generates the configuration elements for the local testing forwarder.
+ *
+ * The local forwarder requires one parameter for the path to the unix socket.
+ *
+ * @code
+ * {
+ * // Configure a stack with {APIConnector,TLVCodec,LocalForwarder}
+ *
+ * stackConfig = ccnxStackConfig_Create();
+ * connConfig = ccnxConnectionConfig_Create();
+ *
+ * apiConnector_ProtocolStackConfig(stackConfig);
+ * apiConnector_ConnectionConfig(connConfig);
+ * tlvCodec_ProtocolStackConfig(stackConfig);
+ * tlvCodec_ConnectionConfig(connConfig);
+ * localForwarder_ProtocolStackConfig(stackConfig);
+ * localForwarder_ConnectionConfig(connConfig, "/var/run/bentpipe.sock");
+ *
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connConfig);
+ * }
+ *
+ */
+
+#ifndef Libccnx_config_Forwarder_Local_h
+#define Libccnx_config_Forwarder_Local_h
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+/**
+ * Generates the configuration settings included in the Protocol Stack configuration
+ *
+ * Adds configuration elements to the Protocol Stack configuration
+ *
+ * { "FWD_LOCAL" : { } }
+ *
+ * @param [in] stackConfig The protocl stack configuration to update
+ *
+ * @return non-null The updated protocol stack configuration
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxStackConfig *localForwarder_ProtocolStackConfig(CCNxStackConfig *stackConfig);
+
+/**
+ * Generates:
+ *
+ */
+
+/**
+ * Generates the configuration settings included in the Connection configuration
+ *
+ * Adds configuration elements to the `CCNxConnectionConfig`
+ *
+ * { "FWD_LOCAL" : { "path" : pipePath } }
+ *
+ * @param [in] config A pointer to a valid CCNxConnectionConfig instance.
+ * @param [in] pipePath The filesystem path to the unix domain socket
+ *
+ * @return non-null The modified `CCNxConnectionConfig`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxConnectionConfig *localForwarder_ConnectionConfig(CCNxConnectionConfig *config, const char *pipePath);
+
+/**
+ * Returns the text string for this component
+ *
+ * Used as the text key to a JSON block. You do not need to free it.
+ *
+ * @return non-null A text string unique to this component
+ *
+ */
+const char *localForwarder_GetName(void);
+
+const char *localForwarder_GetPath(PARCJSON *connectionJson);
+#endif // Libccnx_config_Forwarder_Local_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Metis.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Metis.c
new file mode 100644
index 00000000..511f738f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Metis.c
@@ -0,0 +1,81 @@
+/*
+ * 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 "config_Forwarder_Metis.h"
+#include <ccnx/transport/transport_rta/core/components.h>
+
+static const char param_METIS_PORT[] = METIS_PORT_ENV; // integer, e.g. 9695
+static const short default_port = 9695;
+
+/**
+ * Generates:
+ *
+ * { "FWD_METIS" : { "port" : port } }
+ */
+CCNxStackConfig *
+metisForwarder_ProtocolStackConfig(CCNxStackConfig *stackConfig)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ CCNxStackConfig *result = ccnxStackConfig_Add(stackConfig, metisForwarder_GetName(), value);
+ parcJSONValue_Release(&value);
+
+ return result;
+}
+
+/**
+ * The metis forwarder port may be set per connection in the stack
+ *
+ * { "FWD_METIS" : { "port" : port } }
+ */
+CCNxConnectionConfig *
+metisForwarder_ConnectionConfig(CCNxConnectionConfig *connConfig, uint16_t port)
+{
+ PARCJSON *json = parcJSON_Create();
+ parcJSON_AddInteger(json, param_METIS_PORT, port);
+
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ parcJSON_Release(&json);
+ CCNxConnectionConfig *result = ccnxConnectionConfig_Add(connConfig, metisForwarder_GetName(), value);
+ parcJSONValue_Release(&value);
+
+ return result;
+}
+
+uint16_t
+metisForwarder_GetDefaultPort()
+{
+ return default_port;
+}
+
+const char *
+metisForwarder_GetName()
+{
+ return RtaComponentNames[FWD_METIS];
+}
+
+uint16_t
+metisForwarder_GetPortFromConfig(PARCJSON *json)
+{
+ PARCJSONValue *value = parcJSON_GetValueByName(json, metisForwarder_GetName());
+ assertNotNull(value, "Got null for %s json", metisForwarder_GetName());
+ PARCJSON *metisJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(metisJson, param_METIS_PORT);
+ return (uint16_t) parcJSONValue_GetInteger(value);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Metis.h b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Metis.h
new file mode 100644
index 00000000..78a0669a
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Forwarder_Metis.h
@@ -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.
+ */
+
+/**
+ * @file config_Forwarder_Metis.h
+ * @brief Generates stack and connection configuration information
+ *
+ * Each component in the protocol stack must have a configuration element.
+ * This module generates the configuration elements for the Metis connector.
+ *
+ * The Metis connector requires one parameter to specify the port.
+ *
+ * @code
+ * {
+ * // Configure a stack with {APIConnector,TLVCodec,MetisConnector}
+ *
+ * stackConfig = ccnxStackConfig_Create();
+ * connConfig = ccnxConnectionConfig_Create();
+ *
+ * apiConnector_ProtocolStackConfig(stackConfig);
+ * apiConnector_ConnectionConfig(connConfig);
+ * tlvCodec_ProtocolStackConfig(stackConfig);
+ * tlvCodec_ConnectionConfig(connConfig);
+ * metisForwarder_ProtocolStackConfig(stackConfig);
+ * metisForwarder_ConnectionConfig(connConfig, metisForwarder_GetDefaultPort());
+ *
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connConfig);
+ * }
+ *
+ */
+
+#ifndef Libccnx_config_Forwarder_Metis_h
+#define Libccnx_config_Forwarder_Metis_h
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+#define METIS_PORT_ENV "METIS_PORT"
+#define FORWARDER_CONNECTION_ENV "CCNX_FORWARDER"
+
+/**
+ * Generates the configuration settings included in the Protocol Stack configuration
+ *
+ * Adds configuration elements to the Protocol Stack configuration
+ *
+ * { "FWD_METIS" : { } }
+ *
+ * @param [in] stackConfig The protocl stack configuration to update
+ *
+ * @return non-null The updated protocol stack configuration
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxStackConfig *metisForwarder_ProtocolStackConfig(CCNxStackConfig *stackConfig);
+
+/**
+ * Generates the configuration settings included in the Connection configuration
+ *
+ * Adds configuration elements to the `CCNxConnectionConfig`
+ *
+ * { "FWD_METIS" : { "port" : port } }
+ *
+ * @param [in] config A pointer to a valid CCNxConnectionConfig instance.
+ *
+ * @return non-null The modified `CCNxConnectionConfig`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxConnectionConfig *metisForwarder_ConnectionConfig(CCNxConnectionConfig *config, uint16_t port);
+
+/**
+ * Returns the text string for this component
+ *
+ * Used as the text key to a JSON block. You do not need to free it.
+ *
+ * @return non-null A text string unique to this component
+ *
+ */
+const char *metisForwarder_GetName(void);
+
+/**
+ * Returns the IANA assigned port for the CCN forwarder
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return 9695 The IANA assigned port for CCN
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint16_t metisForwarder_GetDefaultPort(void);
+
+/**
+ * Return the metis port ot use (or the default 9695) based on the setting
+ * in the per-connection configuration
+ */
+uint16_t metisForwarder_GetPortFromConfig(PARCJSON *json);
+
+#endif // Libccnx_config_Forwarder_Metis_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_InMemoryVerifier.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_InMemoryVerifier.c
new file mode 100644
index 00000000..8f76c184
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_InMemoryVerifier.c
@@ -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.
+ */
+
+//
+// config_InMemoryVerifier.c
+// Libccnx
+//
+//
+
+#include <config.h>
+#include <stdio.h>
+#include "config_InMemoryVerifier.h"
+
+#include <ccnx/transport/transport_rta/core/components.h>
+
+#include <LongBow/runtime.h>
+
+static const char name[] = "InMemoryVerifier";
+
+/**
+ * Generates:
+ *
+ * { "SIGNER" : "InMemoryVerifier",
+ * }
+ */
+CCNxConnectionConfig *
+inMemoryVerifier_ConnectionConfig(CCNxConnectionConfig *connConfig)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ CCNxConnectionConfig *result = ccnxConnectionConfig_Add(connConfig, inMemoryVerifier_GetName(), value);
+ parcJSONValue_Release(&value);
+
+ return result;
+}
+
+const char *
+inMemoryVerifier_GetName(void)
+{
+ return name;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_InMemoryVerifier.h b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_InMemoryVerifier.h
new file mode 100644
index 00000000..3cd5bd65
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_InMemoryVerifier.h
@@ -0,0 +1,81 @@
+/*
+ * 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 config_InMemoryVerifier.h
+ * @brief Generates stack and connection configuration information
+ *
+ * Each component in the protocol stack must have a configuration element.
+ * This module generates the configuration elements for the InMemoryVerifier.
+ *
+ * The InMemoryVerifier sits beside the Codec. The user sends ControlPlaneInformation (CPI)
+ * messages down to the InMemoryVerifier to configure it with keys. Only those keys specified
+ * as trusted will verify content objects.
+ *
+ * @code
+ * {
+ * // Configure a stack with {APIConnector,TLVCodec,MetisConnector}
+ *
+ * stackConfig = ccnxStackConfig_Create();
+ * connConfig = ccnxConnectionConfig_Create();
+ *
+ * apiConnector_ProtocolStackConfig(stackConfig);
+ * apiConnector_ConnectionConfig(connConfig);
+ * tlvCodec_ProtocolStackConfig(stackConfig);
+ * tlvCodec_ConnectionConfig(connConfig);
+ *
+ * inMemoryVerifier_ConnectionConfig(connConfig);
+ *
+ * metisForwarder_ProtocolStackConfig(stackConfig);
+ * metisForwarder_ConnectionConfig(connConfig, metisForwarder_GetDefaultPort());
+ *
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connConfig);
+ * }
+ *
+ */
+
+#ifndef Libccnx_config_InMemoryVerifier_h
+#define Libccnx_config_InMemoryVerifier_h
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+/**
+ * Generates the configuration settings included in the Connection configuration
+ *
+ * Adds configuration elements to the `CCNxConnectionConfig`
+ *
+ * { "VERIFIER" : "InMemoryVerifier" }
+ *
+ * @param [in] config A pointer to a valid CCNxConnectionConfig instance.
+ *
+ * @return non-null The modified `CCNxConnectionConfig`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxConnectionConfig *inMemoryVerifier_ConnectionConfig(CCNxConnectionConfig *config);
+
+/**
+ * Returns the text string for this component
+ *
+ * Used as the text key to a JSON block. You do not need to free it.
+ *
+ * @return non-null A text string unique to this component
+ *
+ */
+const char *inMemoryVerifier_GetName(void);
+#endif // Libccnx_config_InMemoryVerifier_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ProtocolStack.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ProtocolStack.c
new file mode 100644
index 00000000..de52c805
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ProtocolStack.c
@@ -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.
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include "config_ProtocolStack.h"
+
+#include <ccnx/transport/transport_rta/core/components.h>
+
+#include <LongBow/runtime.h>
+
+static const char param_STACK[] = "STACK";
+static const char param_COMPONENTS[] = "COMPONENTS";
+
+/*
+ * Call with the names of each component, terminated by a NULL, for example:
+ *
+ * <code>
+ * ccnxStackConfig_AppendComponents(stackConfig, apiConnector_GetName(), vegasFlowController_GetName(),
+ * tlvCodec_GetName(), localForwarder_GetName(), NULL);
+ * </code>
+ *
+ * Generates:
+ *
+ * { "STACK" : { "COMPONENTS" : [ name1, name2, ... ] }
+ */
+CCNxStackConfig *
+protocolStack_ComponentsConfigArgs(CCNxStackConfig *stackConfig, ...)
+{
+ PARCArrayList *list = parcArrayList_Create(NULL);
+
+ va_list ap;
+ const char *componentName;
+ va_start(ap, stackConfig);
+
+ while ((componentName = va_arg(ap, const char *)) != NULL) {
+ parcArrayList_Add(list, (char *) componentName);
+ }
+
+ va_end(ap);
+
+ stackConfig = protocolStack_ComponentsConfigArrayList(stackConfig, list);
+ parcArrayList_Destroy(&list);
+
+ return stackConfig;
+}
+
+/**
+ * Same as <code>protocolStack_ComponentsConfigArgs</code>, except uses
+ * an ArrayList of <code>const char *</code> component names.
+ */
+CCNxStackConfig *
+protocolStack_ComponentsConfigArrayList(CCNxStackConfig *stackConfig, const PARCArrayList *listOfComponentNames)
+{
+ PARCJSON *stackJson = parcJSON_Create();
+ PARCJSONArray *arrayJson = parcJSONArray_Create();
+
+ for (int i = 0; i < parcArrayList_Size(listOfComponentNames); i++) {
+ char *componentName = parcArrayList_Get(listOfComponentNames, i);
+ PARCJSONValue *value = parcJSONValue_CreateFromCString(componentName);
+ parcJSONArray_AddValue(arrayJson, value);
+ parcJSONValue_Release(&value);
+ }
+
+ parcJSON_AddArray(stackJson, param_COMPONENTS, arrayJson);
+ parcJSONArray_Release(&arrayJson);
+
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(stackJson);
+ parcJSON_Release(&stackJson);
+
+ CCNxStackConfig *result = ccnxStackConfig_Add(stackConfig, param_STACK, value);
+ parcJSONValue_Release(&value);
+ return result;
+}
+
+const char *
+protocolStack_GetName(void)
+{
+ return param_STACK;
+}
+
+/**
+ * Parse the protocol stack json to extract an array list of the component names
+ */
+PARCArrayList *
+protocolStack_GetComponentNameArray(PARCJSON *protocolStackJson)
+{
+ // created with NULL destroyer because we're putting in const char *
+ PARCArrayList *arraylist = parcArrayList_Create_Capacity(NULL, NULL, 16);
+
+ PARCJSONValue *value = parcJSON_GetValueByName(protocolStackJson, param_STACK);
+ assertNotNull(value, "Cannot have null %s key in json", param_STACK);
+ PARCJSON *stackJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(stackJson, param_COMPONENTS);
+ assertNotNull(value, "Cannot have null %s key in json", param_COMPONENTS);
+ assertTrue(parcJSONValue_IsArray(value), "key %s not type ARRAY", param_COMPONENTS);
+ PARCJSONArray *componentsJson = parcJSONValue_GetArray(value);
+
+ size_t length = parcJSONArray_GetLength(componentsJson);
+
+ for (size_t i = 0; i < length; i++) {
+ value = parcJSONArray_GetValue(componentsJson, i);
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ parcArrayList_Add(arraylist, parcBuffer_Overlay(sBuf, 0));
+ }
+ return arraylist;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ProtocolStack.h b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ProtocolStack.h
new file mode 100644
index 00000000..8248f4a3
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_ProtocolStack.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 config_ProtocolStack.h
+ * @brief Generates stack and connection configuration information
+ *
+ * Each component in the protocol stack must have a configuration element.
+ * This module generates the configuration elements for the ProtocolStack.
+ *
+ * The ProtocolStack configuration is a list of key names for the components
+ * in the stack. It is an in-order list of the components to configure in the
+ * stack.
+ *
+ * @code
+ * {
+ * // Configure a stack with {APIConnector,TLVCodec,MetisConnector}
+ *
+ * stackConfig = ccnxStackConfig_Create();
+ * connConfig = ccnxConnectionConfig_Create();
+ *
+ * apiConnector_ProtocolStackConfig(stackConfig);
+ * apiConnector_ConnectionConfig(connConfig);
+ * tlvCodec_ProtocolStackConfig(stackConfig);
+ * tlvCodec_ConnectionConfig(connConfig);
+ * inMemoryVerifier_ConnectionConfig(connConfig);
+ * metisForwarder_ProtocolStackConfig(stackConfig);
+ * metisForwarder_ConnectionConfig(connConfig, metisForwarder_GetDefaultPort());
+ *
+ * protocolStack_ComponentsConfigArgs(stackConfig, apiConnector_Name(), tlvCodec_Name(), metisForwarder_Name(), NULL);
+ *
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connConfig);
+ * }
+ *
+ */
+
+#ifndef Libccnx_config_ProtocolStack_h
+#define Libccnx_config_ProtocolStack_h
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+#include <parc/algol/parc_ArrayList.h>
+
+/**
+ * Generates the configuration settings included in the Protocol Stack configuration
+ *
+ * Adds configuration elements to the Protocol Stack configuration
+ *
+ * { "COMPONENTS" : [ name1, name2, ... ] }
+ *
+ * The ProtocolStack function adds a configuration element that enumerates each component
+ * that will be in the protocol stack, in order. These names must match the names
+ * used by each component in its own particular configuration.
+ *
+ * @param [in] stackConfig The protocl stack configuration to update
+ *
+ * @return non-null The updated protocol stack configuration
+ *
+ * Example:
+ * @code
+ * {
+ * protocolStack_ComponentsConfigArgs(stackConfig, apiConnector_Name(), tlvCodec_Name(), metisForwarder_Name(), NULL);
+ * }
+ * @endcode
+ */
+CCNxStackConfig *protocolStack_ComponentsConfigArgs(CCNxStackConfig *stackConfig, ...);
+
+/**
+ * Generates the configuration settings included in the Protocol Stack configuration
+ *
+ * Adds configuration elements to the Protocol Stack configuration
+ *
+ * { "COMPONENTS" : [ name1, name2, ... ] }
+ *
+ * The ProtocolStack function adds a configuration element that enumerates each component
+ * that will be in the protocol stack, in order. These names must match the names
+ * used by each component in its own particular configuration.
+ *
+ * @param [in] stackConfig The protocl stack configuration to update
+ *
+ * @return non-null The updated protocol stack configuration
+ *
+ * Example:
+ * @code
+ * @endcode
+ */
+CCNxStackConfig *protocolStack_ComponentsConfigArrayList(CCNxStackConfig *stackConfig, const PARCArrayList *listOfComponentNames);
+
+/**
+ * Returns the text string for this component
+ *
+ * Used as the text key to a JSON block. You do not need to free it.
+ *
+ * @return non-null A text string unique to this component
+ *
+ */
+const char *protocolStack_GetName(void);
+
+/**
+ * Parse the protocol stack json to extract an array list of the component names
+ */
+PARCArrayList *protocolStack_GetComponentNameArray(PARCJSON *stackJson);
+#endif // Libccnx_config_ProtocolStack_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_PublicKeySigner.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_PublicKeySigner.c
new file mode 100644
index 00000000..3114e7b6
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_PublicKeySigner.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.
+ */
+
+//
+// config_PublicKeySigner.c
+// Libccnx
+//
+//
+//
+#include <config.h>
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+
+#include <parc/security/parc_Identity.h>
+#include "config_PublicKeySigner.h"
+
+#include <ccnx/transport/transport_rta/core/components.h>
+
+static const char name[] = "publicKeySigner";
+
+static const char param_KEYSTORE_NAME[] = "KEYSTORE_NAME";
+static const char param_KEYSTORE_PASSWD[] = "KEYSTORE_PASSWD";
+static const char param_SIGNER[] = "SIGNER";
+
+/**
+ * Generates:
+ *
+ * { "SIGNER" : "publicKeySigner",
+ * "publicKeySigner" : { "filename" : filename, "password" : password }
+ * }
+ */
+CCNxConnectionConfig *
+configPublicKeySigner_SetIdentity(CCNxConnectionConfig *connConfig, const PARCIdentity *identity)
+{
+ return publicKeySigner_ConnectionConfig(connConfig,
+ parcIdentity_GetFileName(identity),
+ parcIdentity_GetPassWord(identity));
+}
+
+CCNxConnectionConfig *
+publicKeySigner_ConnectionConfig(CCNxConnectionConfig *connConfig, const char *filename, const char *password)
+{
+ assertNotNull(connConfig, "Parameter connConfig must be non-null");
+ assertNotNull(filename, "Parameter filename must be non-null");
+ assertNotNull(password, "Parameter password must be non-null");
+
+ PARCJSONValue *signerNameJson = parcJSONValue_CreateFromCString((char *) publicKeySigner_GetName());
+ ccnxConnectionConfig_Add(connConfig, param_SIGNER, signerNameJson);
+ parcJSONValue_Release(&signerNameJson);
+
+ PARCJSON *keystoreJson = parcJSON_Create();
+ parcJSON_AddString(keystoreJson, param_KEYSTORE_NAME, filename);
+ parcJSON_AddString(keystoreJson, param_KEYSTORE_PASSWD, password);
+
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(keystoreJson);
+ parcJSON_Release(&keystoreJson);
+ CCNxConnectionConfig *result = ccnxConnectionConfig_Add(connConfig, publicKeySigner_GetName(), value);
+ parcJSONValue_Release(&value);
+ return result;
+}
+
+const char *
+publicKeySigner_GetName()
+{
+ return name;
+}
+
+/**
+ * If successful, return true and fill in the parameters in the output argument
+ */
+bool
+publicKeySigner_GetConnectionParams(PARCJSON *connectionJson, struct publickeysigner_params *output)
+{
+ assertNotNull(connectionJson, "Parameter connectionJson must be non-null");
+ assertNotNull(output, "Parameter output must be non-null");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(connectionJson, publicKeySigner_GetName());
+ assertNotNull(value, "JSON key %s missing", publicKeySigner_GetName());
+ PARCJSON *keystoreJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(keystoreJson, param_KEYSTORE_NAME);
+ assertNotNull(value, "JSON key %s missing inside %s", param_KEYSTORE_NAME, publicKeySigner_GetName());
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ output->filename = parcBuffer_Overlay(sBuf, 0);
+
+ value = parcJSON_GetValueByName(keystoreJson, param_KEYSTORE_PASSWD);
+ assertNotNull(value, "JSON key %s missing inside %s", param_KEYSTORE_PASSWD, publicKeySigner_GetName());
+ sBuf = parcJSONValue_GetString(value);
+ output->password = parcBuffer_Overlay(sBuf, 0);
+
+
+ return true;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_PublicKeySigner.h b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_PublicKeySigner.h
new file mode 100644
index 00000000..61fe893c
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_PublicKeySigner.h
@@ -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.
+ */
+
+/**
+ * @file config_PublicKeySigner.h
+ * @brief Generates stack and connection configuration information
+ *
+ * Each component in the protocol stack must have a configuration element.
+ * This module generates the configuration elements for the PKCS12 Signer.
+ *
+ * The signer only as a Connection configuration.
+ *
+ * @code
+ * {
+ * // Configure a stack with {APIConnector,TLVCodec,PKCS12Signer,MetisConnector}
+ *
+ * stackConfig = ccnxStackConfig_Create();
+ * connConfig = ccnxConnectionConfig_Create();
+ *
+ * apiConnector_ProtocolStackConfig(stackConfig);
+ * apiConnector_ConnectionConfig(connConfig);
+ * tlvCodec_ProtocolStackConfig(stackConfig);
+ * tlvCodec_ConnectionConfig(connConfig);
+ *
+ * publicKeySigner_ConnectionConfig(connConfig, "~/.ccnx/keystore.p12", "foobar password");
+ *
+ * metisForwarder_ProtocolStackConfig(stackConfig);
+ * metisForwarder_ConnectionConfig(connConfig, metisForwarder_GetDefaultPort());
+ *
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connConfig);
+ * }
+ *
+ */
+#ifndef Libccnx_config_PublicKeySigner_h
+#define Libccnx_config_PublicKeySigner_h
+#include <stdbool.h>
+
+#include <parc/security/parc_Identity.h>
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+struct publickeysigner_params {
+ const char *filename;
+ const char *password;
+};
+
+/**
+ * Generates the configuration settings included in the Connection configuration
+ *
+ * Adds configuration elements to the `CCNxConnectionConfig`
+ *
+ * { "SIGNER" : "publicKeySigner",
+ * "publicKeySigner" : { "filename" : filename, "password" : password }
+ * }
+ *
+ * @param [in] config A pointer to a valid CCNxConnectionConfig instance.
+ *
+ * @return non-null The modified `CCNxConnectionConfig`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxConnectionConfig *publicKeySigner_ConnectionConfig(CCNxConnectionConfig *config, const char *filename, const char *password);
+
+/**
+ * Generates the configuration settings included in the CCNxConnectionConfig for the identity of the configuration 'owner'
+ *
+ * Adds configuration elements to the `CCNxConnectionConfig`
+ *
+ * { "SIGNER" : "publicKeySigner",
+ * "publicKeySigner" : { "filename" : filename, "password" : password }
+ * }
+ *
+ * @param [in] connConfig The pointer to a valid CCNxConnectionConfig instance.
+ * @param [in] identity A pointer to a valid PARCIdentity instance.
+ *
+ * @return non-null The modified `CCNxConnectionConfig`
+ */
+CCNxConnectionConfig *configPublicKeySigner_SetIdentity(CCNxConnectionConfig *connConfig, const PARCIdentity *identity);
+
+/**
+ * Returns the text string for this component
+ *
+ * Used as the text key to a JSON block. You do not need to free it.
+ *
+ * @return non-null A text string unique to this component
+ *
+ */
+const char *publicKeySigner_GetName(void);
+
+/**
+ * If successful, return true and fill in the parameters in the output argument
+ *
+ * Parses the JSON created by publicKeySigner_ConnectionConfig() and fills in the
+ * output parameter. The output parameter must be allocated by the caller.
+ */
+bool publicKeySigner_GetConnectionParams(PARCJSON *connectionJson, struct publickeysigner_params *output);
+#endif // Libccnx_config_PublicKeySigner_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Signer.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Signer.c
new file mode 100644
index 00000000..ae386c3b
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Signer.c
@@ -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.
+ */
+
+//
+// config_Signer.c
+// Libccnx
+//
+//
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include "config_Signer.h"
+#include "config_PublicKeySigner.h"
+#include "config_SymmetricKeySigner.h"
+
+#include <ccnx/transport/transport_rta/core/components.h>
+
+#include <LongBow/runtime.h>
+
+static const char param_SIGNER[] = "SIGNER";
+
+const char *
+signer_GetName()
+{
+ return param_SIGNER;
+}
+
+/**
+ * Determine which signer is configured
+ */
+SignerType
+signer_GetImplementationType(PARCJSON *connectionJson)
+{
+ assertNotNull(connectionJson, "Parameter must be non-null");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(connectionJson, signer_GetName());
+ assertNotNull(value, "signer must be specified in the connection configuration");
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ const char *signer_name = parcBuffer_Overlay(sBuf, 0);
+
+ assertNotNull(signer_name, "Name of signer must be non-null in connection configuration");
+
+ if (strcasecmp(signer_name, publicKeySigner_GetName()) == 0) {
+ return SignerType_PublicKeySigner;
+ }
+
+ if (strcasecmp(signer_name, symmetricKeySigner_GetName()) == 0) {
+ return SignerType_SymmetricKeySigner;
+ }
+
+ return SignerType_Unknown;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Signer.h b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Signer.h
new file mode 100644
index 00000000..230c55f3
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_Signer.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 config_Signer.h
+ * @brief Queries the configuration to determine which signer is used
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef Libccnx_config_Signer_h
+#define Libccnx_config_Signer_h
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+#include "config_SymmetricKeySigner.h"
+#include "config_PublicKeySigner.h"
+
+typedef enum {
+ SignerType_Unknown,
+ SignerType_PublicKeySigner,
+ SignerType_SymmetricKeySigner
+} SignerType;
+
+/**
+ * Determine which signer is configured. Each specific implementation will emit a line
+ * such as { "SIGNER" : "signer_name" }
+ */
+SignerType signer_GetImplementationType(PARCJSON *connectionJson);
+
+/**
+ * Returns the text string for this component
+ *
+ * Used as the text key to a JSON block. You do not need to free it.
+ *
+ * @return non-null A text string unique to this component
+ *
+ */
+const char *signer_GetName(void);
+#endif // Libccnx_config_Signer_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_SymmetricKeySigner.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_SymmetricKeySigner.c
new file mode 100644
index 00000000..5326af31
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_SymmetricKeySigner.c
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+//
+// config_SymmetricKeySigner.c
+// Libccnx
+//
+//
+
+#include <config.h>
+#include <stdio.h>
+#include "config_SymmetricKeySigner.h"
+
+#include <ccnx/transport/transport_rta/core/components.h>
+
+#include <LongBow/runtime.h>
+
+static const char name[] = "SymmetricKeySigner";
+
+static const char param_KEYSTORE_NAME[] = "KEYSTORE_NAME";
+static const char param_KEYSTORE_PASSWD[] = "KEYSTORE_PASSWD";
+static const char param_SIGNER[] = "SIGNER";
+
+/**
+ * Generates:
+ *
+ * { "SIGNER" : "SymmetricKeySigner",
+ * "SymmetricKeySigner" : { "filename" : filename, "password" : password }
+ * }
+ */
+CCNxConnectionConfig *
+symmetricKeySigner_ConnectionConfig(CCNxConnectionConfig *connConfig, const char *filename, const char *password)
+{
+ assertNotNull(connConfig, "Parameter connConfig must be non-null");
+ assertNotNull(filename, "Parameter filename must be non-null");
+ assertNotNull(password, "Parameter password must be non-null");
+
+ PARCJSONValue *signerNameJson = parcJSONValue_CreateFromCString((char *) symmetricKeySigner_GetName());
+ ccnxConnectionConfig_Add(connConfig, param_SIGNER, signerNameJson);
+ parcJSONValue_Release(&signerNameJson);
+
+ PARCJSON *keystoreJson = parcJSON_Create();
+ parcJSON_AddString(keystoreJson, param_KEYSTORE_NAME, filename);
+ parcJSON_AddString(keystoreJson, param_KEYSTORE_PASSWD, password);
+
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(keystoreJson);
+ parcJSON_Release(&keystoreJson);
+
+ ccnxConnectionConfig_Add(connConfig, symmetricKeySigner_GetName(), value);
+ parcJSONValue_Release(&value);
+ return connConfig;
+}
+
+const char *
+symmetricKeySigner_GetName()
+{
+ return name;
+}
+
+/**
+ * If successful, return true and fill in the parameters in the output argument
+ */
+bool
+symmetricKeySigner_GetConnectionParams(PARCJSON *connectionJson, struct symmetrickeysigner_params *output)
+{
+ assertNotNull(connectionJson, "Parameter connectionJson must be non-null");
+ assertNotNull(output, "Parameter output must be non-null");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(connectionJson, symmetricKeySigner_GetName());
+ assertNotNull(value, "JSON key %s missing", symmetricKeySigner_GetName());
+ PARCJSON *keystoreJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(keystoreJson, param_KEYSTORE_NAME);
+ assertNotNull(value, "JSON key %s missing inside %s", param_KEYSTORE_NAME, symmetricKeySigner_GetName());
+ PARCBuffer *sBuf = parcJSONValue_GetString(value);
+ output->filename = parcBuffer_Overlay(sBuf, 0);
+
+ value = parcJSON_GetValueByName(keystoreJson, param_KEYSTORE_PASSWD);
+ assertNotNull(value, "JSON key %s missing inside %s", param_KEYSTORE_PASSWD, symmetricKeySigner_GetName());
+ sBuf = parcJSONValue_GetString(value);
+ output->password = parcBuffer_Overlay(sBuf, 0);
+ return true;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_SymmetricKeySigner.h b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_SymmetricKeySigner.h
new file mode 100644
index 00000000..0de4be3f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_SymmetricKeySigner.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 config_SymmetricKeySigner.h
+ * @brief Generates stack and connection configuration information
+ *
+ * Each component in the protocol stack must have a configuration element.
+ * This module generates the configuration elements for the Symmetric Keystore.
+ * The keystore is specific to a Connection, so there is no Protocol Stack configuration.
+ *
+ * @code
+ * {
+ * // Configure a stack with {APIConnector,TLVCodec,MetisConnector}
+ * // The coded will use a symmetric keystore
+ *
+ * stackConfig = ccnxStackConfig_Create();
+ * connConfig = ccnxConnectionConfig_Create();
+ *
+ * apiConnector_ProtocolStackConfig(stackConfig);
+ * apiConnector_ConnectionConfig(connConfig);
+ * tlvCodec_ProtocolStackConfig(stackConfig);
+ * tlvCodec_ConnectionConfig(connConfig);
+ * symmetricKeySigner_ConnectionConfig(connConfig, "~/.ccnx/keystore.p12", "foobar password");
+ *
+ * metisForwarder_ProtocolStackConfig(stackConfig);
+ * metisForwarder_ConnectionConfig(connConfig, metis_port);
+ *
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connConfig);
+ * }
+ *
+ */
+
+#ifndef Libccnx_config_SymmetricKeySigner_h
+#define Libccnx_config_SymmetricKeySigner_h
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+#include <stdbool.h>
+
+struct symmetrickeysigner_params {
+ const char *filename;
+ const char *password;
+};
+
+/**
+ * Generates the configuration settings included in the Connection configuration
+ *
+ * Adds configuration elements to the `CCNxConnectionConfig`
+ *
+ * { "SIGNER" : "SymmetricFileStore",
+ * "SymmetricFileStore" : { "filename" : filename, password : password }
+ * }
+ *
+ * @param [in] config A pointer to a valid CCNxConnectionConfig instance.
+ *
+ * @return non-null The modified `CCNxConnectionConfig`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxConnectionConfig *symmetricKeySigner_ConnectionConfig(CCNxConnectionConfig *config, const char *filename, const char *password);
+
+/**
+ * Returns the text string for this component
+ *
+ * Used as the text key to a JSON block. You do not need to free it.
+ *
+ * @return non-null A text string unique to this component
+ *
+ */
+const char *symmetricKeySigner_GetName(void);
+
+/**
+ * Look inside a JSON configuration and extract the Signer parameters
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [out] output The filename and password passed down the stack
+ *
+ * @return true Configuration item found and output set
+ * @return false Configuration item not found, output not set
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool symmetricKeySigner_GetConnectionParams(PARCJSON *connectionJson, struct symmetrickeysigner_params *output);
+#endif // Libccnx_config_SymmetricKeySigner_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_TestingComponent.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_TestingComponent.c
new file mode 100644
index 00000000..1f12bc9b
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_TestingComponent.c
@@ -0,0 +1,73 @@
+/*
+ * 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 "config_TestingComponent.h"
+
+#include <ccnx/transport/transport_rta/core/components.h>
+
+CCNxStackConfig *
+testingUpper_ProtocolStackConfig(CCNxStackConfig *stackConfig)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ CCNxStackConfig *result = ccnxStackConfig_Add(stackConfig, testingUpper_GetName(), value);
+ parcJSONValue_Release(&value);
+
+ return result;
+}
+
+CCNxStackConfig *
+testingLower_ProtocolStackConfig(CCNxStackConfig *stackConfig)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ CCNxStackConfig *result = ccnxStackConfig_Add(stackConfig, testingLower_GetName(), value);
+ parcJSONValue_Release(&value);
+
+ return result;
+}
+
+CCNxConnectionConfig *
+testingUpper_ConnectionConfig(CCNxConnectionConfig *connConfig)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ CCNxConnectionConfig *result = ccnxConnectionConfig_Add(connConfig, testingUpper_GetName(), value);
+ parcJSONValue_Release(&value);
+
+ return result;
+}
+
+CCNxConnectionConfig *
+testingLower_ConnectionConfig(CCNxConnectionConfig *connConfig)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ CCNxConnectionConfig *result = ccnxConnectionConfig_Add(connConfig, testingLower_GetName(), value);
+ parcJSONValue_Release(&value);
+
+ return result;
+}
+
+const char *
+testingUpper_GetName()
+{
+ return RtaComponentNames[TESTING_UPPER];
+}
+
+const char *
+testingLower_GetName()
+{
+ return RtaComponentNames[TESTING_LOWER];
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_TestingComponent.h b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_TestingComponent.h
new file mode 100644
index 00000000..a8c6e83b
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/config_TestingComponent.h
@@ -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.
+ */
+
+/**
+ * @file config_TestingComponent.h
+ * @brief Generates stack and connection configuration information
+ *
+ * Each component in the protocol stack must have a configuration element.
+ * This module generates the configuration elements for a testing component
+ * to be used in unit tests. The upper and lower testing components surround
+ * a component under test to simulate feeding in or sending out messages.
+ *
+ * @code
+ * {
+ * // Configure a stack with {TestingUpper,TLVCodec,TestingLower}
+ *
+ * stackConfig = ccnxStackConfig_Create();
+ * connConfig = ccnxConnectionConfig_Create();
+ *
+ * testingUpper_ProtocolStackConfig(stackConfig);
+ * testingUpper_ConnectionConfig(connConfig);
+ * tlvCodec_ProtocolStackConfig(stackConfig);
+ * tlvCodec_ConnectionConfig(connConfig);
+ * testingLower_ProtocolStackConfig(stackConfig);
+ * testingLower_ConnectionConfig(connConfig, metis_port);
+ *
+ * CCNxTransportConfig *config = ccnxTransportConfig_Create(stackConfig, connConfig);
+ * }
+ *
+ */
+
+#ifndef Libccnx_config_TestingComponent_h
+#define Libccnx_config_TestingComponent_h
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+/**
+ * Generates the configuration settings included in the Protocol Stack configuration
+ *
+ * Adds configuration elements to the Protocol Stack configuration
+ *
+ * { "TESTING UPPER" : { } }
+ *
+ * @param [in] stackConfig The protocl stack configuration to update
+ *
+ * @return non-null The updated protocol stack configuration
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxStackConfig *testingUpper_ProtocolStackConfig(CCNxStackConfig *stackConfig);
+
+/**
+ * Generates the configuration settings included in the Protocol Stack configuration
+ *
+ * Adds configuration elements to the Protocol Stack configuration
+ *
+ * { "TESTING LOWER" : { } }
+ *
+ * @param [in] stackConfig The protocl stack configuration to update
+ *
+ * @return non-null The updated protocol stack configuration
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxStackConfig *testingLower_ProtocolStackConfig(CCNxStackConfig *stackConfig);
+
+/**
+ * Generates the configuration settings included in the Connection configuration
+ *
+ * Adds configuration elements to the `CCNxConnectionConfig`
+ *
+ * @param [in] config A pointer to a valid `CCNxConnectionConfig` instance.
+ *
+ * @return non-null A pointer to the modified `CCNxConnectionConfig` instance
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxConnectionConfig *testingUpper_ConnectionConfig(CCNxConnectionConfig *config);
+
+/**
+ * Generates the configuration settings included in the Connection configuration
+ *
+ * Adds configuration elements to the `CCNxConnectionConfig`
+ *
+ * @param [in] config A pointer to a valid `CCNxConnectionConfig` instance.
+ *
+ * @return non-null The modified `CCNxConnectionConfig`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CCNxConnectionConfig *testingLower_ConnectionConfig(CCNxConnectionConfig *config);
+
+
+/**
+ * Returns the text string for this component
+ *
+ * Used as the text key to a JSON block. You do not need to free it.
+ *
+ * @return non-null A text string unique to this component
+ *
+ */
+const char *testingUpper_GetName(void);
+
+/**
+ * Returns the text string for this component
+ *
+ * Used as the text key to a JSON block. You do not need to free it.
+ *
+ * @return non-null A text string unique to this component
+ *
+ */
+const char *testingLower_GetName(void);
+#endif // Libccnx_config_TestingComponent_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/CMakeLists.txt b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/CMakeLists.txt
new file mode 100644
index 00000000..235ef4be
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_config_ApiConnector
+ test_config_Codec_Tlv
+ test_config_FlowControl_Vegas
+ test_config_Forwarder_Local
+ test_config_Forwarder_Metis
+ test_config_InMemoryVerifier
+ test_config_ProtocolStack
+ test_config_PublicKeySigner
+ test_config_Signer
+ test_config_SymmetricKeySigner
+ test_config_TestingComponent
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_ApiConnector.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_ApiConnector.c
new file mode 100644
index 00000000..10abcbd8
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_ApiConnector.c
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+/**
+ * Rta component configuration class unit test
+ *
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../config_ApiConnector.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "testrig_RtaConfigCommon.c"
+
+LONGBOW_TEST_RUNNER(config_ApiConnector)
+{
+ // 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(config_ApiConnector)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(config_ApiConnector)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, apiConnector_ConnectionConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, apiConnector_ConnectionConfig_ReturnValue);
+ LONGBOW_RUN_TEST_CASE(Global, apiConnector_GetName);
+ LONGBOW_RUN_TEST_CASE(Global, apiConnector_ProtocolStackConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, apiConnector_ProtocolStackConfig_ReturnValue);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, testRtaConfiguration_CommonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ testRtaConfiguration_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, apiConnector_ConnectionConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxConnectionConfig *test = apiConnector_ConnectionConfig(data->connConfig);
+
+ assertTrue(test == data->connConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, apiConnector_ConnectionConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ConnectionJsonKey(apiConnector_ConnectionConfig(data->connConfig),
+ apiConnector_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, apiConnector_GetName)
+{
+ testRtaConfiguration_ComponentName(apiConnector_GetName, RtaComponentNames[API_CONNECTOR]);
+}
+
+LONGBOW_TEST_CASE(Global, apiConnector_ProtocolStackConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ProtocolStackJsonKey(apiConnector_ProtocolStackConfig(data->stackConfig),
+ apiConnector_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, apiConnector_ProtocolStackConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxStackConfig *test = apiConnector_ProtocolStackConfig(data->stackConfig);
+
+ assertTrue(test == data->stackConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->stackConfig);
+}
+
+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(config_ApiConnector);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Codec_Tlv.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Codec_Tlv.c
new file mode 100644
index 00000000..d3159bb1
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Codec_Tlv.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.
+ */
+
+/**
+ * Rta component configuration class unit test
+ *
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../config_Codec_Tlv.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "testrig_RtaConfigCommon.c"
+
+LONGBOW_TEST_RUNNER(config_Codec_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(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(config_Codec_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(config_Codec_Tlv)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, Codec_Tlv_ConnectionConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, Codec_Tlv_ConnectionConfig_ReturnValue);
+ LONGBOW_RUN_TEST_CASE(Global, Codec_Tlv_GetName);
+ LONGBOW_RUN_TEST_CASE(Global, Codec_Tlv_ProtocolStackConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, Codec_Tlv_ProtocolStackConfig_ReturnValue);
+
+ LONGBOW_RUN_TEST_CASE(Global, tlvCodec_ConnectionConfig);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, testRtaConfiguration_CommonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ testRtaConfiguration_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, Codec_Tlv_ConnectionConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxConnectionConfig *test = tlvCodec_ConnectionConfig(data->connConfig);
+
+ assertTrue(test == data->connConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, Codec_Tlv_ConnectionConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ConnectionJsonKey(tlvCodec_ConnectionConfig(data->connConfig),
+ tlvCodec_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, Codec_Tlv_GetName)
+{
+ testRtaConfiguration_ComponentName(tlvCodec_GetName, RtaComponentNames[CODEC_TLV]);
+}
+
+LONGBOW_TEST_CASE(Global, Codec_Tlv_ProtocolStackConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ProtocolStackJsonKey(tlvCodec_ProtocolStackConfig(data->stackConfig),
+ tlvCodec_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, Codec_Tlv_ProtocolStackConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxStackConfig *test = tlvCodec_ProtocolStackConfig(data->stackConfig);
+
+ assertTrue(test == data->stackConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->stackConfig);
+}
+
+LONGBOW_TEST_CASE(Global, tlvCodec_ConnectionConfig)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ConnectionJsonKey(tlvCodec_ConnectionConfig(data->connConfig),
+ tlvCodec_GetName());
+
+ PARCJSON *json = ccnxConnectionConfig_GetJson(data->connConfig);
+ assertNotNull(json, "Expected a non-NULL connectionConfig.");
+}
+
+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(config_Codec_Tlv);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_FlowControl_Vegas.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_FlowControl_Vegas.c
new file mode 100644
index 00000000..84e8349d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_FlowControl_Vegas.c
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+/**
+ * Rta component configuration class unit test
+ *
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../config_FlowControl_Vegas.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "testrig_RtaConfigCommon.c"
+
+LONGBOW_TEST_RUNNER(config_FlowControl_Vegas)
+{
+ // 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(config_FlowControl_Vegas)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(config_FlowControl_Vegas)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, FlowControl_Vegas_ConnectionConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, FlowControl_Vegas_ConnectionConfig_ReturnValue);
+ LONGBOW_RUN_TEST_CASE(Global, FlowControl_Vegas_GetName);
+ LONGBOW_RUN_TEST_CASE(Global, FlowControl_Vegas_ProtocolStackConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, FlowControl_Vegas_ProtocolStackConfig_ReturnValue);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, testRtaConfiguration_CommonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ testRtaConfiguration_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, FlowControl_Vegas_ConnectionConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxConnectionConfig *test = vegasFlowController_ConnectionConfig(data->connConfig);
+
+ assertTrue(test == data->connConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, FlowControl_Vegas_ConnectionConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ConnectionJsonKey(vegasFlowController_ConnectionConfig(data->connConfig),
+ vegasFlowController_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, FlowControl_Vegas_GetName)
+{
+ testRtaConfiguration_ComponentName(vegasFlowController_GetName, RtaComponentNames[FC_VEGAS]);
+}
+
+LONGBOW_TEST_CASE(Global, FlowControl_Vegas_ProtocolStackConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ProtocolStackJsonKey(vegasFlowController_ProtocolStackConfig(data->stackConfig),
+ vegasFlowController_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, FlowControl_Vegas_ProtocolStackConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxStackConfig *test = vegasFlowController_ProtocolStackConfig(data->stackConfig);
+
+ assertTrue(test == data->stackConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->stackConfig);
+}
+
+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(config_FlowControl_Vegas);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Forwarder_Local.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Forwarder_Local.c
new file mode 100644
index 00000000..39d82172
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Forwarder_Local.c
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+/**
+ * Rta component configuration class unit test
+ *
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../config_Forwarder_Local.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "testrig_RtaConfigCommon.c"
+
+LONGBOW_TEST_RUNNER(config_Forwarder_Local)
+{
+ // 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(config_Forwarder_Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(config_Forwarder_Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, Forwarder_Local_ConnectionConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, Forwarder_Local_ConnectionConfig_ReturnValue);
+ LONGBOW_RUN_TEST_CASE(Global, Forwarder_Local_GetName);
+ LONGBOW_RUN_TEST_CASE(Global, Forwarder_Local_ProtocolStackConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, Forwarder_Local_ProtocolStackConfig_ReturnValue);
+
+ LONGBOW_RUN_TEST_CASE(Global, Forwarder_Local_GetPath);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, testRtaConfiguration_CommonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ testRtaConfiguration_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, Forwarder_Local_ConnectionConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxConnectionConfig *test = localForwarder_ConnectionConfig(data->connConfig, "/path/to/socket");
+
+ assertTrue(test == data->connConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, Forwarder_Local_ConnectionConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ConnectionJsonKey(localForwarder_ConnectionConfig(data->connConfig, "/path/to/socket"),
+ localForwarder_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, Forwarder_Local_GetName)
+{
+ testRtaConfiguration_ComponentName(localForwarder_GetName, RtaComponentNames[FWD_LOCAL]);
+}
+
+LONGBOW_TEST_CASE(Global, Forwarder_Local_GetPath)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ const char *truth = "/path/to/socket";
+ localForwarder_ConnectionConfig(data->connConfig, truth);
+ const char *test = localForwarder_GetPath(ccnxConnectionConfig_GetJson(data->connConfig));
+ assertTrue(strcmp(truth, test) == 0, "Got wrong socket path, got %s expected %s", test, truth);
+}
+
+LONGBOW_TEST_CASE(Global, Forwarder_Local_ProtocolStackConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ProtocolStackJsonKey(localForwarder_ProtocolStackConfig(data->stackConfig),
+ localForwarder_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, Forwarder_Local_ProtocolStackConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxStackConfig *test = localForwarder_ProtocolStackConfig(data->stackConfig);
+
+ assertTrue(test == data->stackConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->stackConfig);
+}
+
+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(config_Forwarder_Local);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Forwarder_Metis.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Forwarder_Metis.c
new file mode 100644
index 00000000..b4c2c8c4
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Forwarder_Metis.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.
+ */
+
+/**
+ * Rta component configuration class unit test
+ *
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../config_Forwarder_Metis.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "testrig_RtaConfigCommon.c"
+
+LONGBOW_TEST_RUNNER(config_Forwarder_Metis)
+{
+ // 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(Metis);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(config_Forwarder_Metis)
+{
+ 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(config_Forwarder_Metis)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, Forwarder_Metis_ConnectionConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, Forwarder_Metis_ConnectionConfig_ReturnValue);
+ LONGBOW_RUN_TEST_CASE(Global, Forwarder_Metis_GetName);
+ LONGBOW_RUN_TEST_CASE(Global, Forwarder_Metis_ProtocolStackConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, Forwarder_Metis_ProtocolStackConfig_ReturnValue);
+
+ LONGBOW_RUN_TEST_CASE(Global, Forwarder_Metis_GetPath);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, testRtaConfiguration_CommonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ testRtaConfiguration_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, Forwarder_Metis_ConnectionConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxConnectionConfig *test = metisForwarder_ConnectionConfig(data->connConfig, 9999);
+
+ assertTrue(test == data->connConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, Forwarder_Metis_ConnectionConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ConnectionJsonKey(metisForwarder_ConnectionConfig(data->connConfig, 9999),
+ metisForwarder_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, Forwarder_Metis_GetName)
+{
+ testRtaConfiguration_ComponentName(metisForwarder_GetName, RtaComponentNames[FWD_METIS]);
+}
+
+LONGBOW_TEST_CASE(Global, Forwarder_Metis_GetPath)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int truth = 9999;
+ metisForwarder_ConnectionConfig(data->connConfig, truth);
+ int test = metisForwarder_GetPortFromConfig(ccnxConnectionConfig_GetJson(data->connConfig));
+ assertTrue(truth == test, "Got wrong socket path, got %d expected %d", test, truth);
+}
+
+LONGBOW_TEST_CASE(Global, Forwarder_Metis_ProtocolStackConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ProtocolStackJsonKey(metisForwarder_ProtocolStackConfig(data->stackConfig),
+ metisForwarder_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, Forwarder_Metis_ProtocolStackConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxStackConfig *test = metisForwarder_ProtocolStackConfig(data->stackConfig);
+
+ assertTrue(test == data->stackConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->stackConfig);
+}
+
+LONGBOW_TEST_FIXTURE(Metis)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Metis)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Metis)
+{
+ 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(config_Forwarder_Metis);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_InMemoryVerifier.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_InMemoryVerifier.c
new file mode 100644
index 00000000..f4455b48
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_InMemoryVerifier.c
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+/**
+ * Rta component configuration class unit test
+ *
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../config_InMemoryVerifier.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "testrig_RtaConfigCommon.c"
+
+LONGBOW_TEST_RUNNER(config_InMemoryVerifier)
+{
+ // 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(config_InMemoryVerifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(config_InMemoryVerifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, InMemoryVerifier_ConnectionConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, InMemoryVerifier_ConnectionConfig_ReturnValue);
+ LONGBOW_RUN_TEST_CASE(Global, InMemoryVerifier_GetName);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, testRtaConfiguration_CommonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ testRtaConfiguration_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, InMemoryVerifier_ConnectionConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxConnectionConfig *test = inMemoryVerifier_ConnectionConfig(data->connConfig);
+
+ assertTrue(test == data->connConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, InMemoryVerifier_ConnectionConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ConnectionJsonKey(inMemoryVerifier_ConnectionConfig(data->connConfig),
+ inMemoryVerifier_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, InMemoryVerifier_GetName)
+{
+ testRtaConfiguration_ComponentName(inMemoryVerifier_GetName, "InMemoryVerifier");
+}
+
+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(config_InMemoryVerifier);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_ProtocolStack.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_ProtocolStack.c
new file mode 100644
index 00000000..d784b2be
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_ProtocolStack.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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../config_ProtocolStack.c"
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include "testrig_RtaConfigCommon.c"
+
+#include <ccnx/transport/common/ccnx_TransportConfig.h>
+
+LONGBOW_TEST_RUNNER(config_ProtocolStack)
+{
+ // 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(config_ProtocolStack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(config_ProtocolStack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, protocolStack_ComponentsConfigArgs);
+ LONGBOW_RUN_TEST_CASE(Global, protocolStack_ComponentsConfigArrayList);
+ LONGBOW_RUN_TEST_CASE(Global, protocolStack_GetComponentNameArray);
+ LONGBOW_RUN_TEST_CASE(Global, protocolStack_GetName);
+}
+
+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, protocolStack_ComponentsConfigArgs)
+{
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+
+ const char truth[] = "{\"STACK\":{\"COMPONENTS\":[\"Apple\",\"Bananna\",\"Cherry\"]}}";
+
+ protocolStack_ComponentsConfigArgs(stackConfig, "Apple", "Bananna", "Cherry", NULL);
+ PARCJSON *json = ccnxStackConfig_GetJson(stackConfig);
+ char *str = parcJSON_ToCompactString(json);
+ assertTrue(strcmp(truth, str) == 0, "Got wrong config, got %s expected %s", str, truth);
+ parcMemory_Deallocate((void **) &str);
+ ccnxStackConfig_Release(&stackConfig);
+}
+
+LONGBOW_TEST_CASE(Global, protocolStack_ComponentsConfigArrayList)
+{
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+ PARCArrayList *names = parcArrayList_Create(NULL);
+ parcArrayList_Add(names, "Apple");
+ parcArrayList_Add(names, "Bananna");
+ parcArrayList_Add(names, "Cherry");
+
+ const char truth[] = "{\"STACK\":{\"COMPONENTS\":[\"Apple\",\"Bananna\",\"Cherry\"]}}";
+
+ protocolStack_ComponentsConfigArrayList(stackConfig, names);
+ PARCJSON *json = ccnxStackConfig_GetJson(stackConfig);
+ char *str = parcJSON_ToCompactString(json);
+ assertTrue(strcmp(truth, str) == 0, "Got wrong config, got %s expected %s", str, truth);
+
+ parcMemory_Deallocate((void **) &str);
+ ccnxStackConfig_Release(&stackConfig);
+ parcArrayList_Destroy(&names);
+}
+
+LONGBOW_TEST_CASE(Global, protocolStack_GetComponentNameArray)
+{
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+ PARCArrayList *names = parcArrayList_Create(NULL);
+ parcArrayList_Add(names, "Apple");
+ parcArrayList_Add(names, "Bananna");
+ parcArrayList_Add(names, "Cherry");
+
+ protocolStack_ComponentsConfigArrayList(stackConfig, names);
+
+ char truth[] = "{\"STACK\":{\"COMPONENTS\":[\"Apple\",\"Bananna\",\"Cherry\"]}}";
+ PARCJSON *json = parcJSON_ParseString(truth);
+
+ PARCArrayList *test = protocolStack_GetComponentNameArray(json);
+
+ assertTrue(parcArrayList_Size(test) == parcArrayList_Size(names),
+ "wrong array list size, got %zu expected %zu",
+ parcArrayList_Size(test), parcArrayList_Size(names));
+ for (int i = 0; i < parcArrayList_Size(test); i++) {
+ char *a = parcArrayList_Get(test, i);
+ char *b = parcArrayList_Get(names, i);
+ assertTrue(strcmp(a, b) == 0, "mismatch elements %d, got %s expected %s", i, a, b);
+ }
+
+ ccnxStackConfig_Release(&stackConfig);
+ parcArrayList_Destroy(&names);
+ parcJSON_Release(&json);
+ parcArrayList_Destroy(&test);
+}
+
+LONGBOW_TEST_CASE(Global, protocolStack_GetName)
+{
+ const char *name = protocolStack_GetName();
+ assertTrue(strcmp(name, param_STACK) == 0, "Got wrong name, got %s expected %s", name, param_STACK);
+}
+
+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(config_ProtocolStack);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_PublicKeySigner.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_PublicKeySigner.c
new file mode 100644
index 00000000..325d4b86
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_PublicKeySigner.c
@@ -0,0 +1,133 @@
+/*
+ * 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_PublicKeySigner.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include "testrig_RtaConfigCommon.c"
+#include <ccnx/transport/transport_rta/config/config_Signer.h>
+
+LONGBOW_TEST_RUNNER(config_PublicKeySignerPkcs12Store)
+{
+ // 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(config_PublicKeySignerPkcs12Store)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(config_PublicKeySignerPkcs12Store)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, publicKeySignerPkcs12Store_ConnectionConfig);
+ LONGBOW_RUN_TEST_CASE(Global, publicKeySignerPkcs12Store_GetConnectionParams);
+ LONGBOW_RUN_TEST_CASE(Global, publicKeySignerPkcs12Store_GetName);
+}
+
+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, publicKeySignerPkcs12Store_ConnectionConfig)
+{
+ CCNxConnectionConfig *connConfig = ccnxConnectionConfig_Create();
+ const char *filename = "filename";
+ const char *password = "password";
+ publicKeySigner_ConnectionConfig(connConfig, filename, password);
+
+ // make sure our stuff is in there
+ testRtaConfiguration_ConnectionJsonKey(connConfig, publicKeySigner_GetName());
+
+ // make sure the SIGNER parameter is in there
+ testRtaConfiguration_ConnectionJsonKey(connConfig, signer_GetName());
+
+ ccnxConnectionConfig_Destroy(&connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, publicKeySignerPkcs12Store_GetConnectionParams)
+{
+ CCNxConnectionConfig *connConfig = ccnxConnectionConfig_Create();
+ const char *filename = "filename";
+ const char *password = "password";
+ publicKeySigner_ConnectionConfig(connConfig, filename, password);
+
+ PARCJSON *json = ccnxConnectionConfig_GetJson(connConfig);
+ struct publickeysigner_params params;
+
+ publicKeySigner_GetConnectionParams(json, &params);
+
+ assertTrue(strncmp(params.filename, filename, strlen(filename)) == 0, "wrong filename, got %s expected %s", params.filename, filename);
+ assertTrue(strncmp(params.password, password, strlen(password)) == 0, "wrong password, got %s expected %s", params.password, password);
+
+ ccnxConnectionConfig_Destroy(&connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, publicKeySignerPkcs12Store_GetName)
+{
+ testRtaConfiguration_ComponentName(&publicKeySigner_GetName, 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;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(config_PublicKeySignerPkcs12Store);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Signer.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Signer.c
new file mode 100644
index 00000000..cf8f3e98
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_Signer.c
@@ -0,0 +1,141 @@
+/*
+ * 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_Signer.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include "testrig_RtaConfigCommon.c"
+
+LONGBOW_TEST_RUNNER(config_Signer)
+{
+ // 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(config_Signer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(config_Signer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, signer_GetImplementationType_PublicKey);
+ LONGBOW_RUN_TEST_CASE(Global, signer_GetImplementationType_SymmetricKey);
+ LONGBOW_RUN_TEST_CASE(Global, signer_GetImplementationType_Unknown);
+ LONGBOW_RUN_TEST_CASE(Global, signer_GetName);
+}
+
+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, signer_GetImplementationType_PublicKey)
+{
+ CCNxConnectionConfig *connConfig = ccnxConnectionConfig_Create();
+ const char *filename = "filename";
+ const char *password = "password";
+ publicKeySigner_ConnectionConfig(connConfig, filename, password);
+
+ PARCJSON *json = ccnxConnectionConfig_GetJson(connConfig);
+
+ SignerType type = signer_GetImplementationType(json);
+ assertTrue(type == SignerType_PublicKeySigner, "Got wrong signer type, got %d expected %d", type, SignerType_PublicKeySigner);
+
+ ccnxConnectionConfig_Destroy(&connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, signer_GetImplementationType_SymmetricKey)
+{
+ CCNxConnectionConfig *connConfig = ccnxConnectionConfig_Create();
+ const char *filename = "filename";
+ const char *password = "password";
+ symmetricKeySigner_ConnectionConfig(connConfig, filename, password);
+
+ PARCJSON *json = ccnxConnectionConfig_GetJson(connConfig);
+
+ SignerType type = signer_GetImplementationType(json);
+ assertTrue(type == SignerType_SymmetricKeySigner, "Got wrong signer type, got %d expected %d", type, SignerType_SymmetricKeySigner);
+
+ ccnxConnectionConfig_Destroy(&connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, signer_GetImplementationType_Unknown)
+{
+ char *bogusSignerString = "{\"SIGNER\":\"BogusSigner\",\"BogusSigner\":{}}";
+
+ PARCJSON *json = parcJSON_ParseString(bogusSignerString);
+
+ SignerType type = signer_GetImplementationType(json);
+ assertTrue(type == SignerType_Unknown, "Got wrong signer type, got %d expected %d", type, SignerType_Unknown);
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(Global, signer_GetName)
+{
+ testRtaConfiguration_ComponentName(&signer_GetName, param_SIGNER);
+}
+
+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(config_Signer);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_SymmetricKeySigner.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_SymmetricKeySigner.c
new file mode 100644
index 00000000..4d6244e1
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_SymmetricKeySigner.c
@@ -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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../config_SymmetricKeySigner.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include "testrig_RtaConfigCommon.c"
+#include <ccnx/transport/transport_rta/config/config_Signer.h>
+
+LONGBOW_TEST_RUNNER(config_SymmetricKeySignerFileStore)
+{
+ // 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(config_SymmetricKeySignerFileStore)
+{
+ 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(config_SymmetricKeySignerFileStore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, symmetricKeySignerFileStore_ConnectionConfig);
+ LONGBOW_RUN_TEST_CASE(Global, symmetricKeySignerFileStore_GetConnectionParams);
+ LONGBOW_RUN_TEST_CASE(Global, symmetricKeySignerFileStore_GetName);
+}
+
+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, symmetricKeySignerFileStore_ConnectionConfig)
+{
+ CCNxConnectionConfig *connConfig = ccnxConnectionConfig_Create();
+ const char *filename = "filename";
+ const char *password = "password";
+ symmetricKeySigner_ConnectionConfig(connConfig, filename, password);
+
+ // make sure our stuff is in there
+ testRtaConfiguration_ConnectionJsonKey(connConfig, symmetricKeySigner_GetName());
+
+ // make sure the SIGNER parameter is in there
+ testRtaConfiguration_ConnectionJsonKey(connConfig, signer_GetName());
+
+ ccnxConnectionConfig_Destroy(&connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, symmetricKeySignerFileStore_GetConnectionParams)
+{
+ CCNxConnectionConfig *connConfig = ccnxConnectionConfig_Create();
+ const char *filename = "filename";
+ const char *password = "password";
+ symmetricKeySigner_ConnectionConfig(connConfig, filename, password);
+
+ PARCJSON *json = ccnxConnectionConfig_GetJson(connConfig);
+ struct symmetrickeysigner_params params;
+
+ symmetricKeySigner_GetConnectionParams(json, &params);
+
+ assertTrue(strncmp(params.filename, filename, strlen(filename)) == 0, "wrong filename, got %s expected %s", params.filename, filename);
+ assertTrue(strncmp(params.password, password, strlen(password)) == 0, "wrong password, got %s expected %s", params.password, password);
+
+ ccnxConnectionConfig_Destroy(&connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, symmetricKeySignerFileStore_GetName)
+{
+ testRtaConfiguration_ComponentName(&symmetricKeySigner_GetName, 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;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(config_SymmetricKeySignerFileStore);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_TestingComponent.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_TestingComponent.c
new file mode 100644
index 00000000..ac8ba52e
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/test_config_TestingComponent.c
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+
+/**
+ * Rta component configuration class unit test
+ *
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../config_TestingComponent.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "testrig_RtaConfigCommon.c"
+
+LONGBOW_TEST_RUNNER(config_TestingComponent)
+{
+ // 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(config_TestingComponent)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(config_TestingComponent)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, testingUpper_ConnectionConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, testingUpper_ConnectionConfig_ReturnValue);
+ LONGBOW_RUN_TEST_CASE(Global, testingUpper_GetName);
+ LONGBOW_RUN_TEST_CASE(Global, testingUpper_ProtocolStackConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, testingUpper_ProtocolStackConfig_ReturnValue);
+
+ LONGBOW_RUN_TEST_CASE(Global, testingLower_ConnectionConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, testingLower_ConnectionConfig_ReturnValue);
+ LONGBOW_RUN_TEST_CASE(Global, testingLower_GetName);
+ LONGBOW_RUN_TEST_CASE(Global, testingLower_ProtocolStackConfig_JsonKey);
+ LONGBOW_RUN_TEST_CASE(Global, testingLower_ProtocolStackConfig_ReturnValue);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, testRtaConfiguration_CommonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ testRtaConfiguration_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, testingUpper_ConnectionConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxConnectionConfig *test = testingUpper_ConnectionConfig(data->connConfig);
+
+ assertTrue(test == data->connConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, testingUpper_ConnectionConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ConnectionJsonKey(testingUpper_ConnectionConfig(data->connConfig),
+ testingUpper_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, testingUpper_GetName)
+{
+ testRtaConfiguration_ComponentName(testingUpper_GetName, RtaComponentNames[TESTING_UPPER]);
+}
+
+LONGBOW_TEST_CASE(Global, testingUpper_ProtocolStackConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ProtocolStackJsonKey(testingUpper_ProtocolStackConfig(data->stackConfig),
+ testingUpper_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, testingUpper_ProtocolStackConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxStackConfig *test = testingUpper_ProtocolStackConfig(data->stackConfig);
+
+ assertTrue(test == data->stackConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->stackConfig);
+}
+
+LONGBOW_TEST_CASE(Global, testingLower_ConnectionConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxConnectionConfig *test = testingLower_ConnectionConfig(data->connConfig);
+
+ assertTrue(test == data->connConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->connConfig);
+}
+
+LONGBOW_TEST_CASE(Global, testingLower_ConnectionConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ConnectionJsonKey(testingUpper_ConnectionConfig(data->connConfig),
+ testingUpper_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, testingLower_GetName)
+{
+ testRtaConfiguration_ComponentName(testingLower_GetName, RtaComponentNames[TESTING_LOWER]);
+}
+
+LONGBOW_TEST_CASE(Global, testingLower_ProtocolStackConfig_JsonKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ testRtaConfiguration_ProtocolStackJsonKey(testingLower_ProtocolStackConfig(data->stackConfig),
+ testingLower_GetName());
+}
+
+LONGBOW_TEST_CASE(Global, testingLower_ProtocolStackConfig_ReturnValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxStackConfig *test = testingLower_ProtocolStackConfig(data->stackConfig);
+
+ assertTrue(test == data->stackConfig,
+ "Did not return pointer to argument for chaining, got %p expected %p",
+ (void *) test, (void *) data->stackConfig);
+}
+
+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(config_TestingComponent);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/testrig_RtaConfigCommon.c b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/testrig_RtaConfigCommon.c
new file mode 100644
index 00000000..29f2da24
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/config/test/testrig_RtaConfigCommon.c
@@ -0,0 +1,66 @@
+/*
+ * 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 test routines for the RTA component configuration functions
+ *
+ */
+
+typedef struct test_data {
+ CCNxConnectionConfig *connConfig;
+ CCNxStackConfig *stackConfig;
+} TestData;
+
+TestData *
+testRtaConfiguration_CommonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->connConfig = ccnxConnectionConfig_Create();
+ data->stackConfig = ccnxStackConfig_Create();
+ return data;
+}
+
+void
+testRtaConfiguration_CommonTeardown(TestData *data)
+{
+ ccnxStackConfig_Release(&data->stackConfig);
+ ccnxConnectionConfig_Destroy(&data->connConfig);
+ parcMemory_Deallocate((void **) &data);
+}
+
+void
+testRtaConfiguration_ComponentName(const char * (*getname)(void), const char *truth)
+{
+ const char *name = getname();
+ assertTrue(strcmp(name, truth) == 0,
+ "Got wrong name, got %s expected %s", name, truth);
+}
+
+void
+testRtaConfiguration_ConnectionJsonKey(CCNxConnectionConfig *configToTest, const char *key)
+{
+ PARCJSON *json = ccnxConnectionConfig_GetJson(configToTest);
+ PARCJSONValue *value = parcJSON_GetValueByName(json, key);
+ assertNotNull(value, "Could not find key %s in configuration json", key);
+}
+
+void
+testRtaConfiguration_ProtocolStackJsonKey(CCNxStackConfig *configToTest, const char *key)
+{
+ PARCJSON *json = ccnxStackConfig_GetJson(configToTest);
+ PARCJSONValue *value = parcJSON_GetValueByName(json, key);
+ assertNotNull(value, "Could not find key %s in configuration json", key);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Api.c b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Api.c
new file mode 100644
index 00000000..7b810adc
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Api.c
@@ -0,0 +1,264 @@
+/*
+ * 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.
+ */
+
+/**
+ * Interface between the event dispatcher and component callbacks to
+ * the RtaApiConnection. The API connector, per se, is implemented in rta_ApiConnection. This
+ * module is the scaffolding to work within the RTA component framework.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <ccnx/transport/transport_rta/connectors/rta_ApiConnection.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Framework_Services.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+#include <ccnx/transport/transport_rta/connectors/connector_Api.h>
+
+#include <ccnx/api/control/controlPlaneInterface.h>
+
+#ifndef DEBUG_OUTPUT
+#define DEBUG_OUTPUT 0
+#endif
+
+static int connector_Api_Init(RtaProtocolStack *stack);
+static int connector_Api_Opener(RtaConnection *conn);
+static void connector_Api_Upcall_Read(PARCEventQueue *, PARCEventType, void *conn);
+static int connector_Api_Closer(RtaConnection *conn);
+static int connector_Api_Release(RtaProtocolStack *stack);
+static void connector_Api_StateChange(RtaConnection *conn);
+
+RtaComponentOperations api_ops =
+{
+ .init = connector_Api_Init,
+ .open = connector_Api_Opener,
+ .upcallRead = connector_Api_Upcall_Read,
+ .upcallEvent = NULL,
+ .downcallRead = NULL,
+ .downcallEvent = NULL,
+ .close = connector_Api_Closer,
+ .release = connector_Api_Release,
+ .stateChange = connector_Api_StateChange
+};
+
+// ========================
+
+static int
+connector_Api_Init(RtaProtocolStack *stack)
+{
+ // nothing to do here
+ if (DEBUG_OUTPUT) {
+ printf("%s init stack %p\n",
+ __func__,
+ (void *) stack);
+ }
+ return 0;
+}
+
+/*
+ * Api_Open will put the RtaConnection as the callback parameter in the UpcallRead,
+ * because its a per-connection descriptor.
+ *
+ * Returns 0 on success, -1 on error
+ */
+static int
+connector_Api_Opener(RtaConnection *connection)
+{
+ RtaComponentStats *stats;
+ RtaApiConnection *apiConnection = rtaApiConnection_Create(connection);
+
+ rtaConnection_SetPrivateData(connection, API_CONNECTOR, apiConnection);
+
+ stats = rtaConnection_GetStats(connection, API_CONNECTOR);
+ assertNotNull(stats, "%s returned null stats\n", __func__);
+ rtaComponentStats_Increment(stats, STATS_OPENS);
+
+ rtaConnection_SetState(connection, CONN_OPEN);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s opened transport_fd %d\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(connection))),
+ __func__,
+ rtaConnection_GetTransportFd(connection));
+
+ printf("%9" PRIu64 " %s open conn %p state %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(connection))),
+ __func__,
+ (void *) connection,
+ (void *) apiConnection);
+ }
+
+ return 0;
+}
+
+/*
+ * Read a message from below in stack
+ * Write a message up to the API
+ */
+static void
+connector_Api_Upcall_Read(PARCEventQueue *eventBuffer, PARCEventType type, void *protocolStackVoid)
+{
+ TransportMessage *tm;
+
+ assertNotNull(protocolStackVoid, "%s called with null ProtocolStack\n", __func__);
+
+ while ((tm = rtaComponent_GetMessage(eventBuffer)) != NULL) {
+ RtaConnection *conn = rtaConnection_GetFromTransport(tm);
+ assertNotNull(conn, "got null connection from transport message\n");
+
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, API_CONNECTOR);
+ assertNotNull(stats, "returned null stats\n");
+
+ rtaComponentStats_Increment(stats, STATS_UPCALL_IN);
+
+ RtaApiConnection *apiConnection = rtaConnection_GetPrivateData(conn, API_CONNECTOR);
+ assertNotNull(apiConnection, "got null apiConnection\n");
+
+ // If we are blocked, only pass control messages
+ if (!rtaConnection_BlockedUp(conn) || transportMessage_IsControl(tm)) {
+ if (!rtaApiConnection_SendToApi(apiConnection, tm, stats)) {
+ // memory is freed at bottom of function
+ }
+ } else {
+ // closed connection, just destroy the message
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s conn %p destroying transport message %p due to closed connection\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) conn,
+ (void *) tm);
+ }
+ }
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s conn %p total upcall reads in %" PRIu64 " out %" PRIu64 "\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) conn,
+ rtaComponentStats_Get(stats, STATS_UPCALL_IN),
+ rtaComponentStats_Get(stats, STATS_UPCALL_OUT));
+ }
+
+ // This is the end of life for the transport message. If the inner TlvDictionary
+ // was put in a CCNxMessage and sent up the stack, then we made another reference to it
+ // so this destroy will not destroy that part.
+ transportMessage_Destroy(&tm);
+ }
+}
+
+/*
+ * The higher layer should no longer be writing to this
+ * socketpair, so we can drain it then close it.
+ */
+static int
+connector_Api_Closer(RtaConnection *conn)
+{
+ RtaComponentStats *stats;
+ RtaApiConnection *apiConnection = rtaConnection_GetPrivateData(conn, API_CONNECTOR);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s starting close conn %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) conn);
+ }
+
+ stats = rtaConnection_GetStats(conn, API_CONNECTOR);
+ assertNotNull(stats, "%s returned null stats\n", __func__);
+ rtaComponentStats_Increment(stats, STATS_CLOSES);
+
+ // This will prevent any new data going in to queues for the connection
+ // Existing messages will be destroyed
+ rtaConnection_SetState(conn, CONN_CLOSED);
+
+ rtaApiConnection_Destroy(&apiConnection);
+ rtaConnection_SetPrivateData(conn, API_CONNECTOR, NULL);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s close conn %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) conn);
+ }
+
+ return 0;
+}
+
+static int
+connector_Api_Release(RtaProtocolStack *stack)
+{
+ // nothing to do here, there's no ProtocolStack state
+ if (DEBUG_OUTPUT) {
+ printf("%s release stack %p\n",
+ __func__,
+ (void *) stack);
+ }
+
+ return 0;
+}
+
+/**
+ * Respond to events for the connection
+ *
+ * Typcially, the forwarder connector will block and unblock the DOWN direction. We need
+ * to stop putting new data in the down directon if its blocked.
+ *
+ * The API connector (us) is generally the thing blocking the UP direction, so we don't need
+ * to respond to those (our own) events.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * ComponentOperations api_ops = {
+ * // [other settings]
+ * .stateChange = connector_Api_StateChange
+ * };
+ * }
+ * @endcode
+ */
+static void
+connector_Api_StateChange(RtaConnection *conn)
+{
+ RtaApiConnection *apiConnection = rtaConnection_GetPrivateData(conn, API_CONNECTOR);
+
+ // we do not test the rtaConnection_BlockedUp() because we are the one setting those
+
+ // If we are blocked in the DOWN direction, disable events on the read queue
+ if (rtaConnection_BlockedDown(conn)) {
+ rtaApiConnection_BlockDown(apiConnection);
+ } else {
+ rtaApiConnection_UnblockDown(apiConnection);
+ }
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Api.h b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Api.h
new file mode 100644
index 00000000..6299116b
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Api.h
@@ -0,0 +1,22 @@
+/*
+ * 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_connector_api_h
+#define Libccnx_connector_api_h
+
+// Function structs for component variations
+extern RtaComponentOperations api_ops;
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Forwarder.h b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Forwarder.h
new file mode 100644
index 00000000..64a3c6e9
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Forwarder.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.
+ */
+
+//
+// connector_Forwarder.h
+// Libccnx
+//
+//
+
+#ifndef Libccnx_connector_fwd_h
+#define Libccnx_connector_fwd_h
+
+// Function structs for component variations
+extern RtaComponentOperations fwd_flan_ops;
+extern RtaComponentOperations fwd_local_ops;
+extern RtaComponentOperations fwd_tlvrtr_ops;
+extern RtaComponentOperations fwd_metis_ops;
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Forwarder_Local.c b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Forwarder_Local.c
new file mode 100644
index 00000000..a434600a
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Forwarder_Local.c
@@ -0,0 +1,552 @@
+/*
+ * 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.
+ */
+
+/**
+ * PF_LOCAL forwarder glue, mostly for testing. This uses a
+ * STREAM socket with a user specified coding. Each message
+ * on the stream is of this format:
+ *
+ * uint32_t process pid
+ * uint32_t user_socket_fd
+ * uint32_t message bytes that follow
+ * uint8_t[] message encoded with user specified codec
+ *
+ * The user_socket_fd will be the same number that the API was assigned
+ * in transportRta_Socket->api_socket_pair[PAIR_OTHER].
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <parc/algol/parc_EventBuffer.h>
+
+#include <LongBow/runtime.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Framework_Services.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+#include <ccnx/transport/transport_rta/connectors/connector_Forwarder.h>
+
+#include <ccnx/transport/transport_rta/config/config_Forwarder_Local.h>
+#include <ccnx/api/control/controlPlaneInterface.h>
+#include <ccnx/api/control/cpi_ControlFacade.h>
+
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+
+#ifndef DEBUG_OUTPUT
+#define DEBUG_OUTPUT 0
+#endif
+
+static int connector_Fwd_Local_Init(RtaProtocolStack *stack);
+static int connector_Fwd_Local_Opener(RtaConnection *conn);
+static void connector_Fwd_Local_Upcall_Read(PARCEventQueue *, PARCEventType, void *conn);
+static void connector_Fwd_Local_Upcall_Event(PARCEventQueue *, PARCEventQueueEventType, void *stack);
+static void connector_Fwd_Local_Downcall_Read(PARCEventQueue *, PARCEventType, void *conn);
+static int connector_Fwd_Local_Closer(RtaConnection *conn);
+static int connector_Fwd_Local_Release(RtaProtocolStack *stack);
+static void connector_Fwd_Local_StateChange(RtaConnection *conn);
+
+RtaComponentOperations fwd_local_ops = {
+ .init = connector_Fwd_Local_Init,
+ .open = connector_Fwd_Local_Opener,
+ .upcallRead = connector_Fwd_Local_Upcall_Read,
+ .upcallEvent = connector_Fwd_Local_Upcall_Event,
+ .downcallRead = connector_Fwd_Local_Downcall_Read,
+ .downcallEvent = NULL,
+ .close = connector_Fwd_Local_Closer,
+ .release = connector_Fwd_Local_Release,
+ .stateChange = connector_Fwd_Local_StateChange
+};
+
+struct fwd_local_state {
+ int fd;
+ PARCEventQueue *bev_local;
+ int connected;
+};
+
+typedef struct {
+ uint32_t pid;
+ uint32_t fd;
+ uint32_t length;
+ uint32_t pad; // make it 16 bytes
+} __attribute__ ((packed)) localhdr;
+
+// ================================
+// NULL
+
+static int
+connector_Fwd_Local_Init(RtaProtocolStack *stack)
+{
+ // no stack-wide initialization
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s init stack %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(stack)),
+ __func__,
+ (void *) stack);
+ }
+ return 0;
+}
+
+/*
+ * Create a PF_LOCAL socket
+ * Set it non-blocking
+ * Wrap it in a buffer event
+ * Set Read and Event callbacks
+ * connect to LOCAL_NAME
+ *
+ * Return 0 success, -1 failure
+ */
+static int
+connector_Fwd_Local_Opener(RtaConnection *conn)
+{
+ PARCEventScheduler *base;
+ RtaProtocolStack *stack;
+ const char *sock_name;
+
+ stack = rtaConnection_GetStack(conn);
+ base = rtaFramework_GetEventScheduler(rtaProtocolStack_GetFramework(stack));
+
+ sock_name = localForwarder_GetPath(rtaConnection_GetParameters(conn));
+ assertNotNull(sock_name, "connector_Fwd_Local_Opener called without setting LOCAL_NAME");
+
+ if (sock_name == NULL) {
+ return -1;
+ }
+
+ struct fwd_local_state *fwd_state = parcMemory_Allocate(sizeof(struct fwd_local_state));
+ assertNotNull(fwd_state, "parcMemory_Allocate(%zu) returned NULL", sizeof(struct fwd_local_state));
+
+ rtaConnection_SetPrivateData(conn, FWD_LOCAL, fwd_state);
+
+ fwd_state->fd = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if (fwd_state->fd < 0) {
+ perror("socket PF_LOCAL");
+ }
+ assertFalse(fwd_state->fd < 0, "socket PF_LOCAL error");
+
+ struct sockaddr_un addr_unix;
+ memset(&addr_unix, 0, sizeof(struct sockaddr_un));
+ addr_unix.sun_family = AF_UNIX;
+
+ trapIllegalValueIf(sizeof(addr_unix.sun_path) <= strlen(sock_name), "sock_name too long, maximum length %zu", sizeof(addr_unix.sun_path) - 1);
+ strcpy(addr_unix.sun_path, sock_name);
+
+ // Setup the socket as non-blocking then wrap in a parcEventQueue.
+
+ int flags = fcntl(fwd_state->fd, F_GETFL, NULL);
+ assertFalse(flags < 0, "fcntl failed to obtain file descriptor flags (%d)\n", errno);
+
+ int failure = fcntl(fwd_state->fd, F_SETFL, flags | O_NONBLOCK);
+ assertFalse(failure, "fcntl failed to set file descriptor flags (%d)\n", errno);
+
+ assertTrue(failure == 0, "could not make socket non-blocking");
+ if (failure < 0) {
+ rtaConnection_SetPrivateData(conn, FWD_LOCAL, NULL);
+ close(fwd_state->fd);
+ parcMemory_Deallocate((void **) &fwd_state);
+ return -1;
+ }
+
+ fwd_state->bev_local = parcEventQueue_Create(base, fwd_state->fd, PARCEventQueueOption_CloseOnFree);
+
+ assertNotNull(fwd_state->bev_local, "Null buffer event for local socket.");
+
+ parcEventQueue_SetCallbacks(fwd_state->bev_local,
+ connector_Fwd_Local_Upcall_Read,
+ NULL,
+ connector_Fwd_Local_Upcall_Event,
+ conn);
+
+ parcEventQueue_Enable(fwd_state->bev_local, PARCEventType_Read);
+
+ memset(&addr_unix, 0, sizeof(addr_unix));
+ addr_unix.sun_family = AF_UNIX;
+
+ trapIllegalValueIf(sizeof(addr_unix.sun_path) <= strlen(sock_name), "sock_name too long, maximum length %zu", sizeof(addr_unix.sun_path) - 1);
+ strcpy(addr_unix.sun_path, sock_name);
+
+ // This will deliver a PARCEventQueue_Connected on connect success
+ if (parcEventQueue_ConnectSocket(fwd_state->bev_local,
+ (struct sockaddr*) &addr_unix,
+ (socklen_t) sizeof(addr_unix)) < 0) {
+ perror("connect PF_LOCAL");
+ assertTrue(0, "connect PF_LOCAL");
+ rtaConnection_SetPrivateData(conn, FWD_LOCAL, NULL);
+ close(fwd_state->fd);
+ parcMemory_Deallocate((void **) &fwd_state);
+ return -1;
+ }
+
+ // Socket will be ready for use once we get PARCEventQueueEventType_Connected
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s open conn %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) conn);
+ }
+
+ return 0;
+}
+
+/*
+ * Read from bev_local. We are passed the connection on the ptr.
+ */
+static void
+connector_Fwd_Local_Upcall_Read(PARCEventQueue *bev, PARCEventType type, void *ptr)
+{
+ RtaConnection *conn = (RtaConnection *) ptr;
+ RtaProtocolStack *stack = rtaConnection_GetStack(conn);
+ PARCEventBuffer *in = parcEventBuffer_GetQueueBufferInput(bev);
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(stack, FWD_LOCAL, RTA_UP);
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, FWD_LOCAL);
+ TransportMessage *tm;
+
+ unsigned char *mem;
+ int res;
+
+ // only move forward if enough bytes available
+
+ while (parcEventBuffer_GetLength(in) >= sizeof(localhdr)) {
+ size_t msg_length;
+
+ mem = parcEventBuffer_Pullup(in, sizeof(localhdr));
+ if (mem == NULL) {
+ // not enough bytes
+ parcEventBuffer_Destroy(&in);
+ return;
+ }
+
+ msg_length = ((localhdr *) mem)->length;
+ if (parcEventBuffer_GetLength(in) < msg_length + sizeof(localhdr)) {
+ // not enough bytes
+ parcEventBuffer_Destroy(&in);
+ return;
+ }
+
+ PARCBuffer *wireFormat = parcBuffer_Allocate(msg_length);
+ assertNotNull(wireFormat, "parcBuffer_Allocate(%zu) returned NULL", msg_length);
+
+ rtaComponentStats_Increment(stats, STATS_UPCALL_IN);
+
+ // we can read a whole message. Read it directly in to a buffer
+ // Skip the FWD_LOCAL header
+ res = parcEventBuffer_Read(in, NULL, sizeof(localhdr));
+ assertTrue(res == 0, "Got error draining header from buffer");
+
+ uint8_t *overlay = parcBuffer_Overlay(wireFormat, msg_length);
+ res = parcEventBuffer_Read(in, overlay, msg_length);
+ overlay = NULL;
+
+ assertTrue(res == msg_length,
+ "parcEventBuffer_Read returned wrong size, expected %zu got %d",
+ msg_length, res);
+
+ parcBuffer_Flip(wireFormat);
+
+ if (rtaConnection_GetState(conn) == CONN_OPEN) {
+ CCNxWireFormatMessage *wireFormatMessage = ccnxWireFormatMessage_Create(wireFormat);
+ CCNxTlvDictionary *dictionary = ccnxWireFormatMessage_GetDictionary(wireFormatMessage);
+ if (dictionary != NULL) {
+ // wrap it for transport module
+ tm = transportMessage_CreateFromDictionary(dictionary);
+
+ // add the connection info to the transport message before sending up stack
+ transportMessage_SetInfo(tm, rtaConnection_Copy(conn), rtaConnection_FreeFunc);
+
+ // send it up the stack
+ if (rtaComponent_PutMessage(out, tm)) {
+ rtaComponentStats_Increment(stats, STATS_UPCALL_OUT);
+ }
+
+ // Now release our hold on the wireFormatMessage (aka dictionary)
+ ccnxWireFormatMessage_Release(&wireFormatMessage);
+ } else {
+ printf("Failed to create CCNxTlvDictionary from wireformat\n");
+ parcBuffer_Display(wireFormat, 3);
+ }
+ } else {
+ //drop packets
+ }
+
+ parcBuffer_Release(&wireFormat);
+ }
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s total upcall reads in %" PRIu64 " out %" PRIu64 "\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ rtaComponentStats_Get(stats, STATS_UPCALL_IN),
+ rtaComponentStats_Get(stats, STATS_UPCALL_OUT));
+ }
+ parcEventBuffer_Destroy(&in);
+}
+
+/*
+ * Event on connection to forwarder.
+ * Passed the RtaConnection in the pointer
+ */
+static void
+connector_Fwd_Local_Upcall_Event(PARCEventQueue *queue, PARCEventQueueEventType events, void *ptr)
+{
+ RtaConnection *conn = (RtaConnection *) ptr;
+
+ struct fwd_local_state *fwd_state = rtaConnection_GetPrivateData(conn, FWD_LOCAL);
+
+ if (events & PARCEventQueueEventType_Connected) {
+ if (DEBUG_OUTPUT) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ printf("%6lu.%06ld %s (pid %d) connected socket %d\n",
+ tv.tv_sec, (long) tv.tv_usec,
+ __func__,
+ getpid(),
+ rtaConnection_GetTransportFd(conn));
+ }
+
+ fwd_state->connected = 1;
+ rtaConnection_SendStatus(conn, FWD_LOCAL, RTA_UP, notifyStatusCode_CONNECTION_OPEN, NULL, NULL);
+ } else if (events & PARCEventQueueEventType_Error) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ longBowRuntime_StackTrace(1);
+
+ if (events & PARCEventQueueEventType_Reading) {
+ printf("%6lu.%06ld %s (pid %d) Got read error on PF_LOCAL, transport socket %d: (%d) %s\n",
+ tv.tv_sec, (long) tv.tv_usec,
+ __func__,
+ getpid(),
+ rtaConnection_GetTransportFd(conn),
+ errno,
+ strerror(errno));
+ } else if (events & PARCEventQueueEventType_Writing) {
+ printf("%6lu.%06ld %s (pid %d) Got write error on PF_LOCAL, transport socket %d: (%d) %s\n",
+ tv.tv_sec, (long) tv.tv_usec,
+ __func__,
+ getpid(),
+ rtaConnection_GetTransportFd(conn),
+ errno,
+ strerror(errno));
+ } else {
+ printf("%6lu.%06ld %s (pid %d) Got error on PF_LOCAL, transport socket %d: (%d) %s\n",
+ tv.tv_sec, (long) tv.tv_usec,
+ __func__,
+ getpid(),
+ rtaConnection_GetTransportFd(conn),
+ errno,
+ strerror(errno));
+ }
+
+ /* An error occured while connecting. */
+ rtaConnection_SendStatus(conn, FWD_LOCAL, RTA_UP, notifyStatusCode_FORWARDER_NOT_AVAILABLE, NULL, NULL);
+ }
+}
+
+static void
+_ackRequest(RtaConnection *conn, PARCJSON *request)
+{
+ PARCJSON *response = cpiAcks_CreateAck(request);
+ CCNxTlvDictionary *ackDict = ccnxControlFacade_CreateCPI(response);
+
+ TransportMessage *tm_ack = transportMessage_CreateFromDictionary(ackDict);
+ ccnxTlvDictionary_Release(&ackDict);
+ parcJSON_Release(&response);
+
+ transportMessage_SetInfo(tm_ack, rtaConnection_Copy(conn), rtaConnection_FreeFunc);
+
+ RtaProtocolStack *stack = rtaConnection_GetStack(conn);
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(stack, FWD_LOCAL, RTA_UP);
+ if (rtaComponent_PutMessage(out, tm_ack)) {
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, FWD_LOCAL);
+ rtaComponentStats_Increment(stats, STATS_UPCALL_OUT);
+ }
+}
+
+static void
+connector_Fwd_Local_ProcessControl(RtaConnection *conn, TransportMessage *tm)
+{
+ CCNxTlvDictionary *controlDictionary = transportMessage_GetDictionary(tm);
+
+ if (ccnxControlFacade_IsCPI(controlDictionary)) {
+ PARCJSON *json = ccnxControlFacade_GetJson(controlDictionary);
+ if (controlPlaneInterface_GetCPIMessageType(json) == CPI_REQUEST) {
+ if (cpi_getCPIOperation2(json) == CPI_PAUSE) {
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s conn %p recieved PAUSE\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) conn);
+ }
+ _ackRequest(conn, json);
+ } else if (cpi_getCPIOperation2(json) == CPI_FLUSH) {
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s conn %p recieved FLUSH\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) conn);
+ }
+ _ackRequest(conn, json);
+ } else {
+ // some other message. We just ACK everything in the local connector.
+ _ackRequest(conn, json);
+ }
+ }
+ }
+}
+
+static void
+connector_Fwd_Local_WriteIovec(struct fwd_local_state *fwdConnState, RtaConnection *conn, CCNxCodecNetworkBufferIoVec *vec, RtaComponentStats *stats)
+{
+ localhdr lh;
+
+ memset(&lh, 0, sizeof(localhdr));
+ lh.pid = getpid();
+ lh.fd = rtaConnection_GetTransportFd(conn);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s total downcall reads %" PRIu64 "\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ rtaComponentStats_Get(stats, STATS_DOWNCALL_IN));
+ }
+
+ int iovcnt = ccnxCodecNetworkBufferIoVec_GetCount(vec);
+ const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+
+ lh.length = 0;
+ for (int i = 0; i < iovcnt; i++) {
+ lh.length += array[i].iov_len;
+ }
+
+ if (parcEventQueue_Write(fwdConnState->bev_local, &lh, sizeof(lh)) < 0) {
+ trapUnrecoverableState("%s error writing to bev_local", __func__);
+ }
+
+ for (int i = 0; i < iovcnt; i++) {
+ if (parcEventQueue_Write(fwdConnState->bev_local, array[i].iov_base, array[i].iov_len) < 0) {
+ trapUnrecoverableState("%s error writing iovec to bev_local", __func__);
+ }
+ }
+}
+
+/* send raw packet from codec to forwarder */
+static void
+connector_Fwd_Local_Downcall_Read(PARCEventQueue *in, PARCEventType event, void *ptr)
+{
+ TransportMessage *tm;
+
+ while ((tm = rtaComponent_GetMessage(in)) != NULL) {
+ RtaConnection *conn;
+ struct fwd_local_state *fwdConnState;
+ RtaComponentStats *stats;
+
+ CCNxTlvDictionary *messageDictionary = transportMessage_GetDictionary(tm);
+
+ conn = rtaConnection_GetFromTransport(tm);
+ fwdConnState = rtaConnection_GetPrivateData(conn, FWD_LOCAL);
+ stats = rtaConnection_GetStats(conn, FWD_LOCAL);
+ rtaComponentStats_Increment(stats, STATS_DOWNCALL_IN);
+
+ // ignore configuration messages for the send
+ if (ccnxTlvDictionary_IsControl(messageDictionary)) {
+ connector_Fwd_Local_ProcessControl(conn, tm);
+ } else {
+ CCNxCodecNetworkBufferIoVec *vec = ccnxWireFormatMessage_GetIoVec(messageDictionary);
+ assertNotNull(vec, "%s got null wire format\n", __func__);
+
+ connector_Fwd_Local_WriteIovec(fwdConnState, conn, vec, stats);
+
+ rtaComponentStats_Increment(stats, STATS_DOWNCALL_OUT);
+ }
+
+ // we can release everything here. connector_Fwd_Local_WriteIovec made its own references
+ // to the wire format if it needed them.
+ transportMessage_Destroy(&tm);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s total downcall reads in %" PRIu64 " out %" PRIu64 "\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ rtaComponentStats_Get(stats, STATS_DOWNCALL_IN),
+ rtaComponentStats_Get(stats, STATS_DOWNCALL_OUT));
+ }
+ }
+}
+
+static int
+connector_Fwd_Local_Closer(RtaConnection *conn)
+{
+ struct fwd_local_state *fwd_state = rtaConnection_GetPrivateData(conn, FWD_LOCAL);
+ RtaComponentStats *stats;
+
+ assertNotNull(fwd_state, "invalid state");
+ assertNotNull(fwd_state->bev_local, "invalid PARCEventQueue pointer");
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s called on fwd_state %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))), __func__, (void *) fwd_state);
+ }
+
+ stats = rtaConnection_GetStats(conn, FWD_LOCAL);
+
+ // this will close too
+ parcEventQueue_Destroy(&(fwd_state->bev_local));
+ memset(fwd_state, 0, sizeof(struct fwd_local_state));
+ parcMemory_Deallocate((void **) &fwd_state);
+
+ rtaConnection_SetPrivateData(conn, FWD_LOCAL, NULL);
+ rtaComponentStats_Increment(stats, STATS_CLOSES);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s closed fwd_state %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))), __func__, (void *) fwd_state);
+ }
+
+ return 0;
+}
+
+static int
+connector_Fwd_Local_Release(RtaProtocolStack *stack)
+{
+ // no stack-wide initialization
+ if (DEBUG_OUTPUT) {
+ printf("%s release stack %p\n",
+ __func__,
+ (void *) stack);
+ }
+
+ return 0;
+}
+
+static void
+connector_Fwd_Local_StateChange(RtaConnection *conn)
+{
+ //not implemented
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Forwarder_Metis.c b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Forwarder_Metis.c
new file mode 100644
index 00000000..59ad1dcb
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/connector_Forwarder_Metis.c
@@ -0,0 +1,1712 @@
+/*
+ * 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.
+ */
+
+/**
+ * The metis connector does the following per connection:
+ * - Opens a TCP socket to Metis
+ * - Creates an "event" for the socket, does not use the buffer to avoid doing extra copy.
+ * - On read events, uses direct socket operations to read in data
+ *
+ * - DOES NOT HANDLE FRAMING ERRORS. If somehow metis and the connector get
+ * out of whack (technical term), there is no recovery.
+ *
+ * - The connection to metis is started in the Opener, but may not complete by the time
+ * the user sends data down in the Downcall_Read. We should not process the Downcall_Read
+ * until we get the Upcall_Event of connected. When we finally get the connected event,
+ * we should make the Downcall_Read pending again (or just call it) to flush the pending
+ * user data out to metis.
+ *
+ * - Because of how we get scheduled, there might be a large batch of messages waiting at the
+ * forwarder. We don't want to put a giant blob up the stack. So, we keep a deque of TransportMessage
+ * and only feed a few at a time up.
+ *
+ * - Accepts both a PARCBuffer or a CCNxCodecNetworkBufferIoVec as the wire format in the DOWN direction.
+ * - The UP direction is always a PARCBuffer right now
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Deque.h>
+#include <parc/algol/parc_EventBuffer.h>
+#include <parc/algol/parc_EventTimer.h>
+#include <parc/algol/parc_Network.h>
+
+#include <ccnx/transport/common/transport_Message.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Framework_Services.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+
+#include "connector_Forwarder.h"
+
+#include <ccnx/transport/transport_rta/config/config_Forwarder_Metis.h>
+
+#include <ccnx/api/control/controlPlaneInterface.h>
+#include <ccnx/api/control/cpi_ControlFacade.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvEncoder.h>
+#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h>
+#include <ccnx/common/internal/ccnx_TlvDictionary.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvPacket.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h>
+
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+
+#define MINIMUM_READ_LENGTH 8
+
+// The message type for a Metis control packet
+#define METIS_CONTROL_TYPE 0xA4
+
+// at most 10MB, this is used as the output buffer down to metis
+#define METIS_OUTPUT_QUEUE_BYTES (10 * 1024 * 1024)
+
+// How big should we try to make the output socket size?
+#define METIS_SEND_SOCKET_BUFFER 65536
+
+// Maximum input backlog in messages, not bytes
+#define METIS_INPUT_QUEUE_MESSAGES 100
+
+#ifndef DEBUG_OUTPUT
+#define DEBUG_OUTPUT 0
+#endif
+
+static int connector_Fwd_Metis_Init(RtaProtocolStack *stack);
+static int connector_Fwd_Metis_Opener(RtaConnection *conn);
+
+static void _eventCallback(int fd, PARCEventType what, void *connectionVoid);
+static void connector_Fwd_Metis_Dequeue(int fd, PARCEventType which_event, void *metisStateVoid);
+
+static void connector_Fwd_Metis_Downcall_Read(PARCEventQueue *, PARCEventType, void *conn);
+static int connector_Fwd_Metis_Closer(RtaConnection *conn);
+static int connector_Fwd_Metis_Release(RtaProtocolStack *stack);
+static void connector_Fwd_Metis_StateChange(RtaConnection *conn);
+
+RtaComponentOperations fwd_metis_ops = {
+ .init = connector_Fwd_Metis_Init,
+ .open = connector_Fwd_Metis_Opener,
+ .upcallRead = NULL,
+ .upcallEvent = NULL,
+ .downcallRead = connector_Fwd_Metis_Downcall_Read,
+ .downcallEvent = NULL,
+ .close = connector_Fwd_Metis_Closer,
+ .release = connector_Fwd_Metis_Release,
+ .stateChange = connector_Fwd_Metis_StateChange
+};
+
+typedef enum {
+ PacketType_Interest,
+ PacketType_ContentObject,
+ PacketType_Control,
+ PacketType_InterestReturn,
+ PacketType_Unknown
+} _PacketType;
+
+typedef struct metis_connector_stats {
+ unsigned countUpcallReads;
+ unsigned countUpcallWriteDataOk;
+ unsigned countUpcallWriteDataError;
+ unsigned countUpcallWriteDataBlocked;
+ unsigned countUpcallWriteDataQueueFull;
+
+ unsigned countUpcallWriteControlOk;
+ unsigned countUpcallWriteControlError;
+
+ unsigned countDowncallReads;
+ unsigned countDowncallWrites;
+ unsigned countDowncallControl;
+} _MetisConnectorStats;
+
+/**
+ * This structure holds the read-ahead data for the next message being read based
+ * on its fixed header
+ */
+typedef struct next_message_header {
+ // this is how we frame received messages on a stream connection. We
+ // wait until we read a complete fixed header, then we can set the length
+ // of that message and keep waiting until we receive at least that many bytes.
+ size_t length;
+
+ // at the time when we parse out the message length from the fixed header,
+ // we also parse out the TLV message type from the fixed header
+ _PacketType packetType;
+ uint8_t version;
+
+ // we will read bytes into this structure
+ union _hdr {
+ CCNxCodecSchemaV1FixedHeader v1;
+ uint8_t buffer[MINIMUM_READ_LENGTH];
+ } fixedHeader;
+
+ uint8_t *readLocation;
+ size_t remainingReadLength;
+
+ // The whole message
+ PARCBuffer *packet;
+} NextMessage;
+
+typedef struct fwd_metis_state {
+ uint16_t port;
+ int fd;
+
+ // separate events for read and write on fd so we can individually enable them
+ PARCEvent *readEvent;
+ PARCEvent *writeEvent;
+
+ bool isConnected;
+
+ // This is our read-ahead of the next message fixed header
+ NextMessage nextMessage;
+
+ // the transportMessageQueueEvent is used to dequeue from the queue.
+ // we make sure its scheduled so long as there's messages in the queue, even if there's
+ // nothing else being read
+ PARCDeque *transportMessageQueue;
+ PARCEventTimer *transportMessageQueueEvent;
+
+ // This buffer is the queue of stuff we need to send to the network
+ PARCEventBuffer *metisOutputQueue;
+
+ _MetisConnectorStats stats;
+} FwdMetisState;
+
+/**
+ * @typedef PacketData
+ * @brief Used to pass a record between reading a packet and sending it up the stack
+ * @discussion Used internally to pass data between functions
+ */
+typedef struct packet_data {
+ FwdMetisState *fwd_state;
+ RtaConnection *conn;
+ PARCEventQueue *out;
+ RtaComponentStats *stats;
+} PacketData;
+
+
+// for debugging
+static unsigned fwd_metis_references_queued = 0;
+static unsigned fwd_metis_references_dequeued = 0;
+static unsigned fwd_metis_references_notqueued = 0;
+
+
+typedef enum {
+ ReadReturnCode_Finished, // read all needed bytes
+ ReadReturnCode_PartialRead, // still need some bytes
+ ReadReturnCode_Closed, // the socket is closed
+ ReadReturnCode_Error, // An error on the socket
+} ReadReturnCode;
+
+// ================================
+
+static void
+_nextMessage_Display(const NextMessage *next, unsigned indent)
+{
+ printf("NextMessage %p length %zu type %d version %u readLocation %p remaining %zu\n",
+ (void *) next, next->length, next->packetType, next->version, (void *) next->readLocation, next->remainingReadLength);
+
+ printf("fixedHeader\n");
+ longBowDebug_MemoryDump((const char *) next->fixedHeader.buffer, MINIMUM_READ_LENGTH);
+
+ if (next->packet) {
+ parcBuffer_Display(next->packet, 3);
+ }
+}
+
+static int
+connector_Fwd_Metis_Init(RtaProtocolStack *stack)
+{
+ struct sigaction ignore_action;
+ ignore_action.sa_handler = SIG_IGN;
+ sigemptyset(&ignore_action.sa_mask);
+ ignore_action.sa_flags = 0;
+ sigaction(SIGPIPE, &ignore_action, NULL);
+
+ return 0;
+}
+
+
+/**
+ * Setup the NextMessage structure to begin reading a fixed header
+ *
+ * All fields are zeroed and the readLocation is set to the first byte of the fixedHeader.
+ * The remainingReadLength is set to the size of the fixedHeader.
+ *
+ * @param [in] next An allocated NextMessage to initialize
+ *
+ * Example:
+ * @code
+ * {
+ * NextMessage nextMessage;
+ * _initializeNextMessage(&nextMessage);
+ * }
+ * @endcode
+ */
+static void
+_initializeNextMessage(NextMessage *next)
+{
+ memset(next, 0, sizeof(NextMessage));
+ next->version = 0xFF;
+ next->packetType = PacketType_Unknown;
+ next->readLocation = next->fixedHeader.buffer;
+ next->remainingReadLength = MINIMUM_READ_LENGTH;
+}
+
+static FwdMetisState *
+connector_Fwd_Metis_CreateConnectionState(PARCEventScheduler *scheduler)
+{
+ FwdMetisState *fwd_state = parcMemory_Allocate(sizeof(FwdMetisState));
+ assertNotNull(fwd_state, "parcMemory_Allocate(%zu) returned NULL", sizeof(FwdMetisState));
+
+ memset(fwd_state, 0, sizeof(FwdMetisState));
+ _initializeNextMessage(&fwd_state->nextMessage);
+
+ fwd_state->fd = 0;
+ fwd_state->readEvent = NULL;
+ fwd_state->writeEvent = NULL;
+ fwd_state->transportMessageQueue = parcDeque_Create();
+ fwd_state->transportMessageQueueEvent = parcEventTimer_Create(scheduler, 0, connector_Fwd_Metis_Dequeue, fwd_state);
+ fwd_state->isConnected = false;
+ fwd_state->metisOutputQueue = parcEventBuffer_Create();
+
+ return fwd_state;
+}
+
+static bool
+_openSocket(FwdMetisState *fwd_state, uint16_t port)
+{
+ fwd_state->port = port;
+ fwd_state->fd = socket(PF_INET, SOCK_STREAM, 0);
+
+ if (fwd_state->fd < 0) {
+ if (DEBUG_OUTPUT) {
+ printf("%9c %s failed to open PF_INET SOCK_STREAM socket: (%d) %s\n",
+ ' ', __func__, errno, strerror(errno));
+ }
+ return false;
+ }
+
+ if (DEBUG_OUTPUT) {
+ printf("%9c %s create socket %d port %u\n",
+ ' ', __func__, fwd_state->fd, fwd_state->port);
+ }
+
+ return true;
+}
+
+/**
+ * @function connector_Fwd_Metis_SetupSocket
+ * @abstract Creates the socket and sets the port, but does not call connect
+ * @discussion
+ * Creates and sets up the socket descriptor. makes it non-blocking.
+ * Sets the port in FwdMetisState.
+ *
+ * This is a full PF_INET socket, not forced to PF_LOCAL.
+ *
+ * The sendbuffer size is set to METIS_OUTPUT_QUEUE_BYTES
+ *
+ * precondition: called _openSocket
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+static bool
+_setupSocket(FwdMetisState *fwd_state)
+{
+ trapUnexpectedStateIf(fwd_state->fd < 1, "Invalid socket %d", fwd_state->fd);
+
+ // Set non-blocking flag
+ int flags = fcntl(fwd_state->fd, F_GETFL, NULL);
+ assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno);
+ int res = fcntl(fwd_state->fd, F_SETFL, flags | O_NONBLOCK);
+
+ if (res < 0) {
+ if (DEBUG_OUTPUT) {
+ printf("%9c %s failed to make socket non-blocking: (%d) %s\n",
+ ' ', __func__, errno, strerror(errno));
+ }
+
+ close(fwd_state->fd);
+ return false;
+ }
+
+ const int sendBufferSize = METIS_SEND_SOCKET_BUFFER;
+ res = setsockopt(fwd_state->fd, SOL_SOCKET, SO_SNDBUF, &sendBufferSize, sizeof(int));
+ if (res < 0) {
+ if (DEBUG_OUTPUT) {
+ printf("%9c %s failed to set SO_SNDBUF to %d: (%d) %s\n",
+ ' ', __func__, sendBufferSize, errno, strerror(errno));
+ }
+ // This is a non-fatal error
+ }
+
+#if defined(SO_NOSIGPIPE)
+ // turn off SIGPIPE, return EPIPE
+ const int on = 1;
+ res = setsockopt(fwd_state->fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
+ if (res < 0) {
+ if (DEBUG_OUTPUT) {
+ printf("%9c %s failed to set SO_NOSIGPIPE to %d: (%d) %s\n",
+ ' ', __func__, sendBufferSize, errno, strerror(errno));
+ }
+ // this is not a fatal error, so keep going
+ }
+#endif
+
+ return true;
+}
+
+/**
+ * @function connector_Fwd_Metis_SetupConnectionBuffer
+ * @abstract Creates the connection buffer and adds it to libevent
+ * @discussion
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+static bool
+_setupSocketEvents(FwdMetisState *fwd_state, RtaConnection *conn)
+{
+ RtaProtocolStack *stack = rtaConnection_GetStack(conn);
+ PARCEventScheduler *scheduler = rtaFramework_GetEventScheduler(rtaProtocolStack_GetFramework(stack));
+
+ // the connect() call will be asynchrnous because the socket is non-blocking, so we
+ // need ET_WRITE to trigger a callback when the socket becomes writable (i.e. connected).
+ // If there's an error on connect it will be an ET_READ | ET_WRITE event with an error on the socket.
+ fwd_state->readEvent = parcEvent_Create(scheduler, fwd_state->fd, PARCEventType_Read | PARCEventType_Persist | PARCEventType_EdgeTriggered, _eventCallback, conn);
+ assertNotNull(fwd_state->readEvent, "Got a null readEvent for socket %d", fwd_state->fd);
+
+ fwd_state->writeEvent = parcEvent_Create(scheduler, fwd_state->fd, PARCEventType_Write | PARCEventType_Persist | PARCEventType_EdgeTriggered, _eventCallback, conn);
+ assertNotNull(fwd_state->writeEvent, "Got a null readEvent for socket %d", fwd_state->fd);
+
+ // Start the write event. It will be signaled on a connect error or when we are connected.
+ // The read event is not enabled until after connect.
+
+ int failure = parcEvent_Start(fwd_state->writeEvent);
+ assertFalse(failure < 0, "Error starting writeEvent event %p: (%d) %s", (void *) fwd_state->writeEvent, errno, strerror(errno));
+
+ return true;
+}
+
+/**
+ * The connection to the forwarder succeeded, step the state machine
+ *
+ * Change the state of the connection to connected and notify the user that it's ready.
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static void
+_connectionSucceeded(FwdMetisState *fwd_state, RtaConnection *conn)
+{
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s Connection %p connected fd %d\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) conn, fwd_state->fd);
+ }
+
+ fwd_state->isConnected = true;
+
+ // enable read events
+ parcEvent_Start(fwd_state->readEvent);
+
+ rtaConnection_SendStatus(conn, FWD_METIS, RTA_UP, notifyStatusCode_CONNECTION_OPEN, NULL, NULL);
+}
+
+static void
+_readInEnvironmentConnectionSpecification(struct sockaddr_in *addr_in)
+{
+ char *forwarderIpEnv = getenv(FORWARDER_CONNECTION_ENV);
+ if (forwarderIpEnv == NULL) {
+ return;
+ }
+
+ char forwarderIpAddress[NI_MAXHOST] = { 0 };
+ in_port_t forwarderIpPort = 0;
+
+ // Currently, we only support tcp control connections to the forwarder
+ sscanf(forwarderIpEnv, "tcp://%[^:]:%hu", forwarderIpAddress, &forwarderIpPort);
+
+ // If provided, use the specified address in a canonical form
+ if (forwarderIpAddress[0] != '\0') {
+ // Normalize the provided hostname
+ struct sockaddr_in *addr = (struct sockaddr_in *) parcNetwork_SockAddress(forwarderIpAddress, forwarderIpPort);
+ char *ipAddress = inet_ntoa(addr->sin_addr);
+ parcMemory_Deallocate(&addr);
+ if (ipAddress) {
+ addr_in->sin_addr.s_addr = inet_addr(ipAddress);
+ } else {
+ addr_in->sin_addr.s_addr = inet_addr(forwarderIpAddress);
+ }
+ }
+
+ // If provided, use the specified port
+ if (forwarderIpPort != 0) {
+ addr_in->sin_port = htons(forwarderIpPort);
+ }
+}
+
+/**
+ * @function connector_Fwd_Metis_BeginConnect
+ * @abstract Begins the non-blocking connect() call to 127.0.0.1 on the port in FwdMetisState
+ * @discussion
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+static bool
+connector_Fwd_Metis_BeginConnect(FwdMetisState *fwd_state, RtaConnection *conn)
+{
+ bool success = false;
+
+ struct sockaddr_in addr_in;
+ memset(&addr_in, 0, sizeof(addr_in));
+ addr_in.sin_port = htons(fwd_state->port);
+ addr_in.sin_family = AF_INET;
+ addr_in.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ // Override defaults if specified
+ _readInEnvironmentConnectionSpecification(&addr_in);
+
+ if (DEBUG_OUTPUT) {
+ char inetAddress[INET_ADDRSTRLEN];
+ inet_ntop(AF_INET, &(addr_in.sin_addr), inetAddress, INET_ADDRSTRLEN);
+ printf("%9" PRIu64 " %s beginning connect socket %d to port %d on %s\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ fwd_state->fd,
+ fwd_state->port,
+ inetAddress);
+ }
+
+ // This will deliver a PARCEventType_Write event on connect success
+ int res = connect(fwd_state->fd, (struct sockaddr*) &addr_in, (socklen_t) sizeof(addr_in));
+
+ if (res == 0) {
+ // connect succeded immediately
+ _connectionSucceeded(fwd_state, conn);
+ success = true;
+ } else if (errno == EINPROGRESS) {
+ // connection is deferred
+ success = true;
+ } else {
+ // a hard error
+ printf("Error connecting: (%d) %s\n", errno, strerror(errno));
+ }
+
+ return success;
+}
+
+/**
+ * We maintain an input queue going up the stack and only dequeue a small number of packets
+ * with each call from the dispatch loop. THis is to avoid bursting a bunch of packets up the stack.
+ */
+static void
+connector_Fwd_Metis_Dequeue(int fd, PARCEventType which_event, void *metisStateVoid)
+{
+ FwdMetisState *fwd_state = (FwdMetisState *) metisStateVoid;
+
+ // random small number. What is right value for this?
+ unsigned max_loops = 6;
+
+ if (DEBUG_OUTPUT) {
+ printf("%9d %s deque size %zu\n",
+ 0,
+ __func__,
+ parcDeque_Size(fwd_state->transportMessageQueue));
+ }
+
+ while (max_loops > 0 && !parcDeque_IsEmpty(fwd_state->transportMessageQueue)) {
+ max_loops--;
+ TransportMessage *tm = parcDeque_RemoveFirst(fwd_state->transportMessageQueue);
+
+ RtaConnection *conn = rtaConnection_GetFromTransport(tm);
+ RtaProtocolStack *stack = rtaConnection_GetStack(conn);
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(stack, FWD_METIS, RTA_UP);
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, FWD_METIS);
+
+ if (rtaComponent_PutMessage(out, tm)) {
+ rtaComponentStats_Increment(stats, STATS_UPCALL_OUT);
+ }
+ }
+
+ // If there are still messages in there, re-schedule
+ if (!parcDeque_IsEmpty(fwd_state->transportMessageQueue)) {
+ if (DEBUG_OUTPUT) {
+ printf("%9d %s rescheduling output queue timer %p\n",
+ 0,
+ __func__,
+ (void *) fwd_state->transportMessageQueueEvent);
+ }
+
+ struct timeval immediateTimeout = { 0, 0 };
+ parcEventTimer_Start(fwd_state->transportMessageQueueEvent, &immediateTimeout);
+ }
+}
+
+/**
+ * Create a TCP socket
+ * Set it non-blocking
+ * Wrap it in a buffer event
+ * Set Read and Event callbacks
+ *
+ * Return 0 success, -1 failure
+ */
+static int
+connector_Fwd_Metis_Opener(RtaConnection *conn)
+{
+ bool success = false;
+
+ uint16_t port = metisForwarder_GetPortFromConfig(rtaConnection_GetParameters(conn));
+
+ PARCEventScheduler *scheduler = rtaFramework_GetEventScheduler(rtaConnection_GetFramework(conn));
+ FwdMetisState *fwd_state = connector_Fwd_Metis_CreateConnectionState(scheduler);
+
+ if (_openSocket(fwd_state, port)) {
+ if (_setupSocket(fwd_state)) {
+ if (_setupSocketEvents(fwd_state, conn)) {
+ if (connector_Fwd_Metis_BeginConnect(fwd_state, conn)) {
+ // stash it away in the per-connection cubby hole
+ rtaConnection_SetPrivateData(conn, FWD_METIS, fwd_state);
+ success = true;
+ }
+ }
+ }
+ }
+
+ if (!success) {
+ if (fwd_state->fd) {
+ close(fwd_state->fd);
+ }
+ if (fwd_state->readEvent) {
+ parcEvent_Destroy(&(fwd_state->readEvent));
+ }
+ if (fwd_state->writeEvent) {
+ parcEvent_Destroy(&(fwd_state->writeEvent));
+ }
+ parcMemory_Deallocate((void **) &fwd_state);
+ return -1;
+ }
+
+ // Socket will be ready for use once we get PARCEventQueue_Connected
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s open conn %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) conn);
+ }
+
+ return 0;
+}
+
+/**
+ * We received a Metis control packet. Translate it to a control packet and send it up the stack.
+ */
+static void
+receiveControlMessage(PacketData *data)
+{
+ CCNxTlvDictionary *packetDictionary =
+ ccnxWireFormatMessage_FromControlPacketType(data->fwd_state->nextMessage.version, data->fwd_state->nextMessage.packet);
+
+ bool success = ccnxCodecTlvPacket_BufferDecode(data->fwd_state->nextMessage.packet, packetDictionary);
+
+ if (success) {
+ TransportMessage *tm = transportMessage_CreateFromDictionary(packetDictionary);
+ transportMessage_SetInfo(tm, rtaConnection_Copy(data->conn), rtaConnection_FreeFunc);
+
+ // send it up the stack
+ if (rtaComponent_PutMessage(data->out, tm)) {
+ rtaComponentStats_Increment(data->stats, STATS_UPCALL_OUT);
+ data->fwd_state->stats.countUpcallWriteControlOk++;
+ } else {
+ data->fwd_state->stats.countUpcallWriteControlError++;
+ }
+ } else {
+ assertTrue(success, "Error decoding a Metis control packet\n")
+ {
+ parcBuffer_Display(data->fwd_state->nextMessage.packet, 3);
+ }
+ }
+
+ // we are now done with our references
+ ccnxTlvDictionary_Release(&packetDictionary);
+}
+
+
+static void
+_queueNonControl(PacketData *data)
+{
+ CCNxTlvDictionary *packetDictionary = ccnxWireFormatMessage_Create(data->fwd_state->nextMessage.packet);
+
+ assertNotNull(packetDictionary, "Got a null packet decode")
+ {
+ parcBuffer_Display(data->fwd_state->nextMessage.packet, 3);
+ }
+
+ TransportMessage *tm = transportMessage_CreateFromDictionary(packetDictionary);
+
+ // add the connection info to the transport message before sending up stack
+ transportMessage_SetInfo(tm, rtaConnection_Copy(data->conn), rtaConnection_FreeFunc);
+
+ parcDeque_Append(data->fwd_state->transportMessageQueue, tm);
+
+ // start if went from emtpy to 1
+ if (parcDeque_Size(data->fwd_state->transportMessageQueue) == 1) {
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s connection %u schedule dequeue event %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(data->conn))),
+ __func__,
+ rtaConnection_GetConnectionId(data->conn),
+ (void *) data->fwd_state->transportMessageQueueEvent);
+ }
+
+ struct timeval immediateTimeout = { 0, 0 };
+ parcEventTimer_Start(data->fwd_state->transportMessageQueueEvent, &immediateTimeout);
+ }
+
+ // we are now done with our references
+ ccnxTlvDictionary_Release(&packetDictionary);
+}
+
+/**
+ * Receive a non-control packet
+ *
+ * Non-control messages may be dropped due to lack of input buffer space.
+ * If the connection has state Block Up or the up queue's length is
+ * too many messages deep, the non-control message will be dropped.
+ *
+ * precondition: the caller knows the message is not a control message
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static void
+_receiveNonControl(PacketData *data)
+{
+ if (rtaConnection_BlockedUp(data->conn)) {
+ data->fwd_state->stats.countUpcallWriteDataBlocked++;
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s connection %u blocked up, drop wireFormat %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(data->conn))),
+ __func__,
+ rtaConnection_GetConnectionId(data->conn),
+ (void *) data->fwd_state->nextMessage.packet);
+ }
+ } else {
+ if (parcDeque_Size(data->fwd_state->transportMessageQueue) < METIS_INPUT_QUEUE_MESSAGES) {
+ _queueNonControl(data);
+ data->fwd_state->stats.countUpcallWriteDataOk++;
+ } else {
+ data->fwd_state->stats.countUpcallWriteDataQueueFull++;
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s connection %u input buffer full, drop wireFormat %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(data->conn))),
+ __func__,
+ rtaConnection_GetConnectionId(data->conn),
+ (void *) data->fwd_state->nextMessage.packet);
+ }
+ }
+ }
+}
+
+/**
+ * We received an entire packet, send it up the stack in a Transport message.
+ *
+ * If its a control message, we make it a CCNxControlMessage here for symmetry with us
+ * encoding the control messages at this level
+ */
+static void
+connector_Fwd_Metis_SendUpStack(PacketData *data)
+{
+ // Always send control messages up the stack
+ if (data->fwd_state->nextMessage.packetType == PacketType_Control) {
+ receiveControlMessage(data);
+ } else {
+ _receiveNonControl(data);
+ }
+}
+
+/**
+ * Return the SO_ERROR value for the given socket
+ *
+ * If getsockopt returns an error, the return code could be the error from getsockopt.
+ *
+ * Typically you will get ECONNREFUSED when you cannot connect and one of the many getsockopt
+ * errors if there's a problem with the actual socket.
+ *
+ * @param [in] fd The socket
+ *
+ * @return errno An errno value
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static int
+_getSocketError(int fd)
+{
+ int value;
+ socklen_t valueLength = sizeof(value);
+ int res = getsockopt(fd, SOL_SOCKET, SO_ERROR, &value, &valueLength);
+ if (res < 0) {
+ value = res;
+ }
+ return value;
+}
+
+/**
+ * Received an event on a socket we have marked as not yet connected
+ *
+ * Ether it's ready to go or there's an error. We will receive a PARCEventType_Read and the socket
+ * will have an SO_ERROR of 0 if it's now connected. If the SO_ERROR is non-zero, there
+ * was an error on connect.
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static void
+_disconnectedEventHandler(FwdMetisState *fwd_state, RtaConnection *conn, PARCEventType what)
+{
+ if (what & PARCEventType_Read) {
+ int socketError = _getSocketError(fwd_state->fd);
+ if (socketError == 0) {
+ // I don't think these happen, they will be write events
+ _connectionSucceeded(fwd_state, conn);
+ } else {
+ // error on connect
+ printf("%9" PRIu64 " %s Connection %p got error on SOCK_STREAM, fd %d: %s\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) conn,
+ fwd_state->fd,
+ strerror(errno));
+
+ // make the event non-pending
+ parcEvent_Stop(fwd_state->readEvent);
+ parcEvent_Stop(fwd_state->writeEvent);
+
+ rtaConnection_SetBlockedDown(conn);
+
+ // at least tell the API whats going on
+ rtaConnection_SendStatus(conn, FWD_METIS, RTA_UP, notifyStatusCode_FORWARDER_NOT_AVAILABLE, NULL, NULL);
+ }
+ }
+
+ if (what & PARCEventType_Write) {
+ int socketError = _getSocketError(fwd_state->fd);
+ if (socketError == 0) {
+ _connectionSucceeded(fwd_state, conn);
+ }
+ }
+}
+
+static void
+_setupNextPacketV1(FwdMetisState *fwd_state)
+{
+ switch (fwd_state->nextMessage.fixedHeader.v1.packetType) {
+ case CCNxCodecSchemaV1Types_PacketType_Interest:
+ fwd_state->nextMessage.packetType = PacketType_Interest;
+ break;
+ case CCNxCodecSchemaV1Types_PacketType_ContentObject:
+ fwd_state->nextMessage.packetType = PacketType_ContentObject;
+ break;
+ case CCNxCodecSchemaV1Types_PacketType_Control:
+ fwd_state->nextMessage.packetType = PacketType_Control;
+ break;
+ case CCNxCodecSchemaV1Types_PacketType_InterestReturn:
+ fwd_state->nextMessage.packetType = PacketType_InterestReturn;
+ break;
+ default:
+ fwd_state->nextMessage.packetType = PacketType_Unknown;
+ break;
+ }
+
+ size_t fixedHeaderLength = sizeof(CCNxCodecSchemaV1FixedHeader);
+ fwd_state->nextMessage.length = htons(fwd_state->nextMessage.fixedHeader.v1.packetLength);
+
+ fwd_state->nextMessage.packet = parcBuffer_Allocate(fwd_state->nextMessage.length);
+ assertNotNull(fwd_state->nextMessage.packet, "Could not allocate packet of size %zu", fwd_state->nextMessage.length);
+
+ // finally copy in the fixed header as we have already read that in
+ parcBuffer_PutArray(fwd_state->nextMessage.packet, fixedHeaderLength, fwd_state->nextMessage.fixedHeader.buffer);
+}
+
+/**
+ * Called after reading whole FixedHeader, will setup the packet buffer
+ *
+ * After reading the fixed header, we need to allocate a PARCBuffer for the packet. Setup that
+ * buffer and copy the FixedHeader in to it. Remaining reads will go in to this buffer.
+ *
+ * After this function completes, the parsed version, packetType, and length of the nextMessage will
+ * be filled in, the packet buffer allocated and the fixedHeader copied to that packet buffer.
+ *
+ * precondition: forwarder->nextMessage.remainingReadLength == 0 && fwd_state->nextMessage.packet == NULL
+ *
+ * @param [in] fwd_state An allocated forwarder connection state that has read in the fixed header
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static void
+_setupNextPacket(FwdMetisState *fwd_state)
+{
+ trapUnexpectedStateIf(fwd_state->nextMessage.packet != NULL, "Calling _setupNextPacket but the packet field is not NULL");
+
+ fwd_state->nextMessage.version = fwd_state->nextMessage.fixedHeader.buffer[0];
+
+ switch (fwd_state->nextMessage.version) {
+ case 1:
+ _setupNextPacketV1(fwd_state);
+ break;
+
+ default:
+ trapUnexpectedState("Illegal packet version %d", fwd_state->nextMessage.version)
+ {
+ _nextMessage_Display(&fwd_state->nextMessage, 0);
+ }
+ break;
+ }
+}
+
+/**
+ * Reads the FixedHeader. If full read will setup the next packet buffer.
+ *
+ * Reads up to FixedHeader length bytes. If read whole header will allocate the next packet
+ * buffer to right size and copy the Fixed Header in to the buffer.
+ *
+ * preconditions:
+ * - fwd_state->nextMessage.packet should be NULL
+ * - fwd_state->nextMessage.remainingReadLength should be the remaining bytes to read of the Fixed Header
+ * - fwd_state->nextMessage.readLocation should point to the location in the FixedHeader to start reading
+ *
+ * postconditions:
+ * - fwd_state->nextMessage.remainingReadLength will be decremented by the amount read
+ * - If remainingReadLength is decremented to 0, will allocate fwd_state->nextMessage.packet and copy in the FixedHeader
+ * - The fields in fwd_state->nextMessage (length, packetType, version) will be set based on the fixed header
+ *
+ * @param [in] fwd_state An allocated forwarder connection state
+ *
+ * @retval ReadReturnCode_Finished one entire packet is ready in the buffer
+ * @retval ReadReturnCode_PartialRead need more bytes
+ * @retval ReadRetrunCode_Closed The socket to metis is closed (a special case of Error)
+ * @retval ReadReturnCode_Error An error occured on the socket to metis
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static ReadReturnCode
+_readPacketHeader(FwdMetisState *fwd_state)
+{
+ ReadReturnCode returnCode = ReadReturnCode_Error;
+
+ // This could be switched to MSG_PEEK instead of copying later, but I don't think it makes any significant change.
+ ssize_t nread = recv(fwd_state->fd, fwd_state->nextMessage.readLocation, fwd_state->nextMessage.remainingReadLength, 0);
+ if (nread > 0) {
+ // recv will always runturn at most fwd_state->nextMessage.remainingReadLength, so this won't wrap around to negative.
+ fwd_state->nextMessage.remainingReadLength -= nread;
+
+ if (fwd_state->nextMessage.remainingReadLength == 0) {
+ returnCode = ReadReturnCode_Finished;
+ _setupNextPacket(fwd_state);
+ } else {
+ fwd_state->nextMessage.readLocation += nread;
+ returnCode = ReadReturnCode_PartialRead;
+ }
+ } else if (nread == 0) {
+ // the connection is closed
+ returnCode = ReadReturnCode_Closed;
+ } else {
+ switch (errno) {
+ case EAGAIN:
+ // call would block. These can happen becasue _readMessage is in a while loop and we detect
+ // the end of the loop because we cannot read another fixed header.
+ returnCode = ReadReturnCode_PartialRead;
+ break;
+
+ default:
+ // an error. I think all errors will be hard errors and we close the connection
+ if (DEBUG_OUTPUT) {
+ printf("%9c %s socket %d recv error: (%d) %s\n",
+ ' ', __func__, fwd_state->fd, errno, strerror(errno));
+ }
+ returnCode = ReadReturnCode_Error;
+ break;
+ }
+ }
+
+ return returnCode;
+}
+
+
+/**
+ * We have finished reading the fixed header, reading the message body
+ *
+ * Will modify the nextMessage.packet buffer. When the buffer has 0 remaining, the whole packet has been read
+ *
+ * precondition: _readHeaderFromMetis read the header and allocated the packet buffer
+ *
+ * @param [in] fwd_state An allocated forwarder connection state
+ *
+ * @retval ReadReturnCode_Finished one entire packet is ready in the buffer
+ * @retval ReadReturnCode_PartialRead need more bytes
+ * @retval ReadRetrunCode_Closed The socket to metis is closed (a special case of Error)
+ * @retval ReadReturnCode_Error An error occured on the socket to metis
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static ReadReturnCode
+_readPacketBody(FwdMetisState *fwd_state)
+{
+ ReadReturnCode returnCode = ReadReturnCode_Error;
+
+ trapUnexpectedStateIf(fwd_state->nextMessage.packet == NULL, "Trying to read a message with a null packet buffer");
+
+ size_t remaining = parcBuffer_Remaining(fwd_state->nextMessage.packet);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9c %s socket %d read up to %zu bytes\n",
+ ' ', __func__, fwd_state->fd, remaining);
+ }
+
+ void *overlay = parcBuffer_Overlay(fwd_state->nextMessage.packet, 0);
+ ssize_t nread = recv(fwd_state->fd, overlay, remaining, 0);
+
+ if (nread > 0) {
+ // good read
+ parcBuffer_SetPosition(fwd_state->nextMessage.packet, parcBuffer_Position(fwd_state->nextMessage.packet) + nread);
+
+ if (nread == remaining) {
+ returnCode = ReadReturnCode_Finished;
+ } else {
+ returnCode = ReadReturnCode_PartialRead;
+ }
+ } else if (nread == 0) {
+ // connection closed
+ returnCode = ReadReturnCode_Closed;
+ } else {
+ switch (errno) {
+ case EAGAIN:
+ // call would block. These can happen becasue _readMessage is in a while loop and we detect
+ // the end of the loop because we cannot read the entire message body.
+ returnCode = ReadReturnCode_PartialRead;
+ break;
+
+ default:
+ // an error. I think all errors will be hard errors and we close the connection
+ if (DEBUG_OUTPUT) {
+ printf("%9c %s socket %d recv error: (%d) %s\n",
+ ' ', __func__, fwd_state->fd, errno, strerror(errno));
+ }
+ returnCode = ReadReturnCode_Error;
+ }
+ }
+
+
+ if (DEBUG_OUTPUT) {
+ printf("%9c %s socket %u msg_length %zu read_length %zd remaining %zu\n",
+ ' ',
+ __func__,
+ fwd_state->fd,
+ fwd_state->nextMessage.length,
+ nread,
+ parcBuffer_Remaining(fwd_state->nextMessage.packet));
+ }
+
+ return returnCode;
+}
+
+/**
+ * Read packet from metis
+ *
+ * Reads the fixed heder. Once fixed header is done, begins reading the packet body. Keeps
+ * all the incremental state to do partial reads.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval ReadReturnCode_Finished one entire packet is ready in the buffer
+ * @retval ReadReturnCode_PartialRead need more bytes
+ * @retval ReadRetrunCode_Closed The socket to metis is closed (a special case of Error)
+ * @retval ReadReturnCode_Error An error occured on the socket to metis
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static ReadReturnCode
+_readPacket(FwdMetisState *fwd_state)
+{
+ ReadReturnCode returnCode = ReadReturnCode_PartialRead;
+
+ // are we still reading the header?
+ if (fwd_state->nextMessage.remainingReadLength > 0) {
+ returnCode = _readPacketHeader(fwd_state);
+ } else {
+ returnCode = ReadReturnCode_Finished;
+ }
+
+ // After reading the header, it may be possible to read the body too
+ if (returnCode == ReadReturnCode_Finished && fwd_state->nextMessage.remainingReadLength == 0) {
+ returnCode = _readPacketBody(fwd_state);
+ }
+
+ return returnCode;
+}
+
+/**
+ * Read as many packets as we can from Metis
+ *
+ * Will read the stream socket from metis until we get a PartialRead return code from
+ * either the attempt to read the header or the body.
+ *
+ * On read error, will send a notification message the connection is closed up to
+ * the API and will disable read and write events.
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static void
+_readFromMetis(FwdMetisState *fwd_state, RtaConnection *conn)
+{
+ RtaProtocolStack *stack = rtaConnection_GetStack(conn);
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, FWD_METIS);
+
+ ReadReturnCode readCode;
+ while ((readCode = _readPacket(fwd_state)) == ReadReturnCode_Finished) {
+ rtaComponentStats_Increment(stats, STATS_UPCALL_IN);
+ fwd_state->stats.countUpcallReads++;
+
+ // setup the buffer for reading
+ parcBuffer_Flip(fwd_state->nextMessage.packet);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s sending packet buffer %p up stack length %zu\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) fwd_state->nextMessage.packet,
+ parcBuffer_Remaining(fwd_state->nextMessage.packet));
+ }
+
+ // this is just to make the signature of connector_Fwd_Metis_SendUpStack tractable, PacketData
+ // is not exposed outside this scope.
+
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(stack, FWD_METIS, RTA_UP);
+ PacketData data = {
+ .fwd_state = fwd_state,
+ .conn = conn,
+ .out = out,
+ .stats = stats,
+ };
+
+ connector_Fwd_Metis_SendUpStack(&data);
+
+ // done with the packet buffer. Release our hold on it. If it was sent up the stack
+ // another reference count was made.
+ parcBuffer_Release(&fwd_state->nextMessage.packet);
+
+ // now setup for next packet
+ _initializeNextMessage(&fwd_state->nextMessage);
+ }
+
+ if (readCode == ReadReturnCode_Closed) {
+ fwd_state->isConnected = false;
+ parcEvent_Stop(fwd_state->readEvent);
+ parcEvent_Stop(fwd_state->writeEvent);
+ rtaConnection_SendStatus(conn, FWD_METIS, RTA_UP, notifyStatusCode_CONNECTION_CLOSED, NULL, "Socket operation returned closed by remote");
+ } else if (readCode == ReadReturnCode_Error) {
+ fwd_state->isConnected = false;
+ parcEvent_Stop(fwd_state->readEvent);
+ parcEvent_Stop(fwd_state->writeEvent);
+ rtaConnection_SendStatus(conn, FWD_METIS, RTA_UP, notifyStatusCode_CONNECTION_CLOSED, NULL, "Socket operation returned error");
+ }
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s total upcall reads in %" PRIu64 " out %" PRIu64 "\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ rtaComponentStats_Get(stats, STATS_UPCALL_IN),
+ rtaComponentStats_Get(stats, STATS_UPCALL_OUT));
+ }
+}
+
+/**
+ * Append a vector to the buffer
+ *
+ * @param [in] wireFormat The wire format packet, assumes current position is start of packet
+ * @param [in] fwd_output The libevent buffer to add the memory reference to
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static void
+_queueIoVecMessageToMetis(CCNxCodecNetworkBufferIoVec *vec, PARCEventBuffer *fwd_output)
+{
+ fwd_metis_references_queued++;
+
+ int iovcnt = ccnxCodecNetworkBufferIoVec_GetCount(vec);
+ const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+
+ for (int i = 0; i < iovcnt; i++) {
+ if (parcEventBuffer_Append(fwd_output, array[i].iov_base, array[i].iov_len) < 0) {
+ trapUnrecoverableState("%s error writing to bev_local", __func__);
+ }
+ }
+}
+
+/**
+ * Append to the buffer
+ *
+ * @param [in] wireFormat The wire format packet, assumes current position is start of packet
+ * @param [in] fwd_output The libevent buffer to add the memory reference to
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static void
+_queueBufferMessageToMetis(PARCBuffer *wireFormat, PARCEventBuffer *fwd_output)
+{
+ fwd_metis_references_queued++;
+
+ void *overlay = parcBuffer_Overlay(wireFormat, 0);
+ size_t length = parcBuffer_Remaining(wireFormat);
+
+ if (parcEventBuffer_Append(fwd_output, overlay, length) < 0) {
+ trapUnrecoverableState("%s error writing to bev_local", __func__);
+ }
+}
+
+/**
+ * Write as much as possible from the output buffer to metis
+ *
+ * Write as much as we can to metis. If there is nothing left, deactivate the write event.
+ * If there is still bytes left in the output buffer, activate the write event.
+ *
+ * postconditions:
+ * - Write as many bytes as possible from the output buffer to metis
+ * - If there are still bytes remaining, enable the write event
+ * - If there are no bytes remaining, disable the write event.
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static void
+_dequeueMessagesToMetis(FwdMetisState *fwdConnState)
+{
+ // if we try to write a 0 length buffer, write will return -1 like an error
+ if (parcEventBuffer_GetLength(fwdConnState->metisOutputQueue) > 0) {
+ fwdConnState->stats.countDowncallWrites++;
+ int nwritten = parcEventBuffer_WriteToFileDescriptor(fwdConnState->metisOutputQueue, fwdConnState->fd, -1);
+ if (nwritten < 0) {
+ // an error
+ trapNotImplemented("Bugzid: 2194");
+ }
+
+ if (DEBUG_OUTPUT) {
+ printf("%9c %s wrote %d bytes to socket %d, %zu bytes remaining\n",
+ ' ',
+ __func__,
+ nwritten,
+ fwdConnState->fd,
+ parcEventBuffer_GetLength(fwdConnState->metisOutputQueue));
+ }
+
+ // if we could not write the whole buffer, make sure we have a write event pending
+ if (parcEventBuffer_GetLength(fwdConnState->metisOutputQueue) > 0) {
+ parcEvent_Start(fwdConnState->writeEvent);
+ if (DEBUG_OUTPUT) {
+ printf("%9c %s enabled write event\n", ' ', __func__);
+ }
+ } else {
+ parcEvent_Stop(fwdConnState->writeEvent);
+ if (DEBUG_OUTPUT) {
+ printf("%9c %s disabled write event\n", ' ', __func__);
+ }
+ }
+ }
+}
+
+
+/**
+ * Called when we get an event on a socket we believe is connected
+ *
+ * libevent will call this with an PARCEventType_Read on connection close too (the read length will be 0).
+ *
+ * @param [in] fwd_state An allocated forwarder connection state
+ * @param [in] conn The corresponding RTA connection
+ * @param [in] what The Libevent set of events
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static void
+_connectedEventHandler(FwdMetisState *fwd_state, RtaConnection *conn, short what)
+{
+ if (what & PARCEventType_Read) {
+ _readFromMetis(fwd_state, conn);
+ }
+
+ if (what & PARCEventType_Write) {
+ _dequeueMessagesToMetis(fwd_state);
+ }
+}
+
+/**
+ * Called for any activity on the socket. Maybe in either connected or disconnected state.
+ */
+static void
+_eventCallback(int fd, PARCEventType what, void *connectionVoid)
+{
+ RtaConnection *conn = (RtaConnection *) connectionVoid;
+ FwdMetisState *fwd_state = (FwdMetisState *) rtaConnection_GetPrivateData(conn, FWD_METIS);;
+
+ if (!fwd_state->isConnected) {
+ _disconnectedEventHandler(fwd_state, conn, what);
+
+ // once we connect, we should try a read immediately too
+ }
+
+ if (fwd_state->isConnected) {
+ _connectedEventHandler(fwd_state, conn, what);
+ }
+}
+
+/**
+ * Updates the connections's Blocked Down state
+ *
+ * If the bytes in our output buffer are greater than METIS_OUTPUT_QUEUE_BYTES, then
+ * we will set the Blocked Down condition on the connection. This will prevent the
+ * API connector from accepting more messages.
+ *
+ * Messages already in the connection queue will still be processed.
+ *
+ * @param [in] fwd_output The libevent buffer to check the backlog
+ * @param [in] conn The RtaConnection the set or clear the blocked down condition
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static void
+_updateBlockedDownState(PARCEventBuffer *fwd_output, RtaConnection *conn)
+{
+ size_t queue_bytes = parcEventBuffer_GetLength(fwd_output);
+ if (queue_bytes > METIS_OUTPUT_QUEUE_BYTES) {
+ // block down
+
+ if (!rtaConnection_BlockedDown(conn)) {
+ rtaConnection_SetBlockedDown(conn);
+ }
+
+ // note that we continue execution and put the packet we have in hand on the queue
+ // setting the blocked down state only affects the API connector. Packets already in the system
+ // will keep flowing down to us
+ } else {
+ // if it is blocked, unblock it
+ if (rtaConnection_BlockedDown(conn)) {
+ rtaConnection_ClearBlockedDown(conn);
+ }
+ }
+}
+
+static void
+connector_Fwd_Metis_Downcall_HandleConnected(FwdMetisState *fwdConnState, TransportMessage *tm, RtaConnection *conn, RtaComponentStats *stats)
+{
+ _updateBlockedDownState(fwdConnState->metisOutputQueue, conn);
+
+ CCNxTlvDictionary *dictionary = transportMessage_GetDictionary(tm);
+
+ bool queued = false;
+
+ CCNxCodecNetworkBufferIoVec *vec = ccnxWireFormatMessage_GetIoVec(dictionary);
+ if (vec != NULL) {
+ _queueIoVecMessageToMetis(vec, fwdConnState->metisOutputQueue);
+ queued = true;
+ } else {
+ PARCBuffer *wireFormat = ccnxWireFormatMessage_GetWireFormatBuffer(dictionary);
+ if (wireFormat != NULL) {
+ _queueBufferMessageToMetis(wireFormat, fwdConnState->metisOutputQueue);
+ queued = true;
+ }
+ }
+
+ if (queued) {
+ rtaComponentStats_Increment(stats, STATS_DOWNCALL_OUT);
+
+ if (DEBUG_OUTPUT) {
+ struct timeval delay = transportMessage_GetDelay(tm);
+ printf("%9" PRIu64 " %s total downcall reads %" PRIu64 " references queued %u dequeued %u not queued %u last delay %.6f\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ rtaComponentStats_Get(stats, STATS_DOWNCALL_IN),
+ fwd_metis_references_queued,
+ fwd_metis_references_dequeued,
+ fwd_metis_references_notqueued,
+ delay.tv_sec + delay.tv_usec * 1E-6);
+ }
+ } else {
+ fwd_metis_references_notqueued++;
+ }
+
+ // The transport message is destroyed in connector_Fwd_Metis_Downcall_Read()
+}
+
+static void
+_ackRequest(RtaConnection *conn, PARCJSON *request)
+{
+ PARCJSON *response = cpiAcks_CreateAck(request);
+ CCNxTlvDictionary *ackDict = ccnxControlFacade_CreateCPI(response);
+
+ TransportMessage *tm_ack = transportMessage_CreateFromDictionary(ackDict);
+ ccnxTlvDictionary_Release(&ackDict);
+ parcJSON_Release(&response);
+
+ transportMessage_SetInfo(tm_ack, rtaConnection_Copy(conn), rtaConnection_FreeFunc);
+
+ RtaProtocolStack *stack = rtaConnection_GetStack(conn);
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(stack, FWD_METIS, RTA_UP);
+ if (rtaComponent_PutMessage(out, tm_ack)) {
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, FWD_METIS);
+ rtaComponentStats_Increment(stats, STATS_UPCALL_OUT);
+ }
+}
+
+static bool
+_handleDownControl(FwdMetisState *fwdConnState, RtaConnection *conn, TransportMessage *tm)
+{
+ bool consumedMessage = false;
+
+ CCNxTlvDictionary *dict = transportMessage_GetDictionary(tm);
+ if (ccnxTlvDictionary_IsControl(dict)) {
+ if (ccnxControlFacade_IsCPI(dict)) {
+ PARCJSON *json = ccnxControlFacade_GetJson(dict);
+ if (controlPlaneInterface_GetCPIMessageType(json) == CPI_REQUEST) {
+ if (cpi_getCPIOperation2(json) == CPI_PAUSE) {
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s conn %p recieved PAUSE\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) conn);
+ }
+ _ackRequest(conn, json);
+ consumedMessage = true;
+ }
+
+ if (cpi_getCPIOperation2(json) == CPI_FLUSH) {
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s conn %p recieved FLUSH\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) conn);
+ }
+ _ackRequest(conn, json);
+ consumedMessage = true;
+ }
+ }
+ }
+ }
+
+ if (consumedMessage) {
+ fwdConnState->stats.countDowncallControl++;
+ }
+
+ return consumedMessage;
+}
+
+/**
+ * send raw packet from codec to forwarder. We are passed the ProtocolStack on the ptr.
+ */
+static void
+connector_Fwd_Metis_Downcall_Read(PARCEventQueue *in, PARCEventType event, void *ptr)
+{
+ TransportMessage *tm;
+
+ while ((tm = rtaComponent_GetMessage(in)) != NULL) {
+ RtaConnection *conn = rtaConnection_GetFromTransport(tm);
+ FwdMetisState *fwdConnState = rtaConnection_GetPrivateData(conn, FWD_METIS);
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, FWD_METIS);
+ rtaComponentStats_Increment(stats, STATS_DOWNCALL_IN);
+ fwdConnState->stats.countDowncallReads++;
+
+ bool consumedControl = _handleDownControl(fwdConnState, conn, tm);
+ if (!consumedControl) {
+ // we did not consume the message as a control packet for the metis connector
+
+ if (fwdConnState->isConnected) {
+ // If the socket is connected, this will "do the right thing" and consume the transport message.
+ connector_Fwd_Metis_Downcall_HandleConnected(fwdConnState, tm, conn, stats);
+ } else {
+ // Oops, got a packet before we're connected.
+ printf("\nConnection %p transport message %p on fd %d that's not open\n", (void *) conn, (void *) tm, fwdConnState->fd);
+ }
+
+ // now attempt to write to the network
+ _dequeueMessagesToMetis(fwdConnState);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s total downcall reads in %" PRIu64 " out %" PRIu64 "\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ rtaComponentStats_Get(stats, STATS_DOWNCALL_IN),
+ rtaComponentStats_Get(stats, STATS_DOWNCALL_OUT));
+ }
+ }
+
+ transportMessage_Destroy(&tm);
+ }
+}
+
+/**
+ * Destroy the FwdMetisState object.
+ *
+ * Destroys any packets waiting in queue, frees the libevent structures used by the connection to Metis.
+ * Frees the FwdMetisState object and will NULL *fwdStatePtr.
+ *
+ * @param [in,out] fwdStatePtr Double pointer to the allocated state. Will be NULL'd on output.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static void
+_fwdMetisState_Release(FwdMetisState **fwdStatePtr)
+{
+ FwdMetisState *fwd_state = *fwdStatePtr;
+
+ while (!parcDeque_IsEmpty(fwd_state->transportMessageQueue)) {
+ TransportMessage *tm = parcDeque_RemoveFirst(fwd_state->transportMessageQueue);
+ transportMessage_Destroy(&tm);
+ }
+
+ parcDeque_Release(&fwd_state->transportMessageQueue);
+
+ if (fwd_state->readEvent) {
+ parcEvent_Destroy(&(fwd_state->readEvent));
+ }
+
+ if (fwd_state->writeEvent) {
+ parcEvent_Destroy(&(fwd_state->writeEvent));
+ }
+
+ parcEventTimer_Destroy(&(fwd_state->transportMessageQueueEvent));
+
+ if (fwd_state->metisOutputQueue) {
+ parcEventBuffer_Destroy(&(fwd_state->metisOutputQueue));
+ }
+
+ if (fwd_state->nextMessage.packet) {
+ parcBuffer_Release(&fwd_state->nextMessage.packet);
+ }
+
+ close(fwd_state->fd);
+
+ parcMemory_Deallocate((void **) &fwd_state);
+ *fwdStatePtr = NULL;
+}
+
+static int
+connector_Fwd_Metis_Closer(RtaConnection *conn)
+{
+ FwdMetisState *fwd_state = rtaConnection_GetPrivateData(conn, FWD_METIS);
+ rtaConnection_SetPrivateData(conn, FWD_METIS, NULL);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s called on fwd_state %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))), __func__, (void *) fwd_state);
+ }
+
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, FWD_METIS);
+ rtaComponentStats_Increment(stats, STATS_CLOSES);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s closed fwd_state %p deque length %zu\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) fwd_state,
+ parcDeque_Size(fwd_state->transportMessageQueue));
+
+ printf("%9" PRIu64 " %s closed fwd_state %p stats: up { reads %u wok %u werr %u wblk %u wfull %u wctrlok %u wctrlerr %u }\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) fwd_state,
+ fwd_state->stats.countUpcallReads, fwd_state->stats.countUpcallWriteDataOk, fwd_state->stats.countUpcallWriteDataError,
+ fwd_state->stats.countUpcallWriteDataBlocked, fwd_state->stats.countUpcallWriteDataQueueFull,
+ fwd_state->stats.countUpcallWriteControlOk, fwd_state->stats.countUpcallWriteControlError);
+
+ printf("%9" PRIu64 " %s closed fwd_state %p stats: dn { reads %u wok %u wctrlok %u }\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) fwd_state,
+ fwd_state->stats.countDowncallReads, fwd_state->stats.countDowncallWrites, fwd_state->stats.countDowncallControl);
+ }
+
+ _fwdMetisState_Release(&fwd_state);
+
+ return 0;
+}
+
+static int
+connector_Fwd_Metis_Release(RtaProtocolStack *stack)
+{
+ return 0;
+}
+
+/**
+ * Enable to disable the read event based on the Blocked Up state
+ *
+ * If we receive a Blocked Up state change and the read event is pending, make it
+ * not pending. If we receive a not blocked up state change and the read event is not
+ * pending, make it pending.
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static void
+connector_Fwd_Metis_StateChange(RtaConnection *conn)
+{
+ struct fwd_metis_state *fwd_state = rtaConnection_GetPrivateData(conn, FWD_METIS);
+
+ int isReadPending = parcEvent_Poll(fwd_state->readEvent, PARCEventType_Read);
+
+
+ // If we are blocked in the UP direction, disable events on the read queue
+ if (rtaConnection_BlockedUp(conn)) {
+ // we only disable it and log it if it was active
+ if (isReadPending) {
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s connection %u blocked up, disable PARCEventType_Read\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ rtaConnection_GetConnectionId(conn));
+ }
+
+ parcEvent_Stop(fwd_state->readEvent);
+ }
+ } else {
+ if ((!isReadPending) && fwd_state->isConnected) {
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s connection %u unblocked up, enable PARCEventType_Read\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ rtaConnection_GetConnectionId(conn));
+ }
+ parcEvent_Start(fwd_state->readEvent);
+ }
+ }
+
+ // We do not need to do anything with DOWN direction, becasue we're the component sending
+ // those block down messages.
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/rta_ApiConnection.c b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/rta_ApiConnection.c
new file mode 100644
index 00000000..4e5ea48f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/rta_ApiConnection.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.
+ */
+
+/**
+ * Implements the API connector. The API connector is a event based component to manage the socket
+ * to the API.
+ *
+ * The API Connector's job is to manage the socket to the API between the RTA Framework and the
+ * API. It does this by using an event directly to manage that socket. It uses the same
+ * event scheduler base as the RTA framework, so its all part of the same event dispatcher.
+ *
+ * The RTA Transport now only speaks CCNxTlvDictionary messages. If we receive old timey Interest,
+ * ContentObject, etc., we translate them to the Dictionary format. The TransportMessage and CCNxMessage
+ * will both go away.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <fcntl.h>
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <errno.h>
+
+#include <parc/algol/parc_EventBuffer.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <LongBow/runtime.h>
+
+#include <ccnx/transport/transport_rta/connectors/rta_ApiConnection.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_Services.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+#include <ccnx/api/control/controlPlaneInterface.h>
+#include <ccnx/api/control/cpi_ControlFacade.h>
+
+#include <ccnx/transport/transport_rta/config/config_Codec_Tlv.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h>
+
+
+#ifndef DEBUG_OUTPUT
+#define DEBUG_OUTPUT 0
+#endif
+
+#define PAIR_TRANSPORT 0
+#define PAIR_OTHER 1
+
+// we are only putting an 8-byte pointer on the queue, so
+// this should be 50 messages
+#define MAX_API_QUEUE_BYTES 400
+
+
+unsigned api_upcall_writes = 0;
+unsigned api_downcall_reads = 0;
+extern unsigned rta_transport_reads;
+
+// per connection state
+struct rta_api_connection {
+ // A reference to our connection
+ RtaConnection *connection;
+
+ // event queue for socketpair to API
+ PARCEventQueue *bev_api;
+
+ // these are assingned to us by the Transport
+ int api_fd;
+ int transport_fd;
+};
+
+// ==========================================================================================
+// STATIC PROTOTYPES and their headerdoc
+
+/**
+ * PARCEvent calls this when the API queue falls below the watermark
+ *
+ * We watermark the write queue at MAX_API_QUEUE_BYTES bytes. When a write takes
+ * the queue backlog below that amount, PARCEvent calls this.
+ *
+ * @param [in] connVoid Void pointer to the RtaConnection
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void rtaApiConnection_WriteCallback(PARCEventQueue *queue, PARCEventType type, void *conn);
+
+/**
+ * PARCEvent calls this when there's a message from the API
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void rtaApiConnection_Downcall_Read(PARCEventQueue *bev, PARCEventType type, void *conn);
+
+/**
+ * PARCEvent calls this when there's a non-read/write event on the API's socket
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void rtaApiConnection_Downcall_Event(PARCEventQueue *, PARCEventQueueEventType events, void *conn);
+
+
+/**
+ * Drains the input queue and output queue of a connection to the API
+ *
+ * The input queue and output queue contain pointers to CCNxMessages. On close,
+ * we need to drain these queues and release all the messages.
+ *
+ * The API Connector is responsible for only draining its input queue. The output
+ * queue up to the API is drained by the RTA Framework.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void rtaApiConnection_DrainApiConnection(RtaApiConnection *apiConnection);
+
+/**
+ * Writes a message to the API
+ *
+ * Takes ownership of the message which is passed up to the API
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void rtaApiConnection_WriteMessageToApi(RtaApiConnection *apiConnection, CCNxMetaMessage *msg);
+
+// ==========================================================================================
+// Public API
+
+static void
+rtaApiConnection_SetupSocket(RtaApiConnection *apiConnection, RtaConnection *connection)
+{
+ RtaProtocolStack *stack = rtaConnection_GetStack(connection);
+ PARCEventScheduler *base = rtaFramework_GetEventScheduler(rtaProtocolStack_GetFramework(stack));
+ int error;
+
+ // Set non-blocking flag
+ int flags = fcntl(apiConnection->transport_fd, F_GETFL, NULL);
+ assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno);
+ int failure = fcntl(apiConnection->transport_fd, F_SETFL, flags | O_NONBLOCK);
+ assertFalse(failure, "fcntl failed to set socket non-blocking(%d) %s\n", errno, strerror(errno));
+
+ apiConnection->bev_api = parcEventQueue_Create(base, apiConnection->transport_fd, 0);
+ assertNotNull(apiConnection->bev_api, "Got null result from parcEventQueue_Create");
+
+ // Set buffer size
+ int sendbuff = 1000 * 8;
+
+ error = setsockopt(rtaConnection_GetTransportFd(connection), SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff));
+ assertTrue(error == 0, "Got error setting SO_SNDBUF: %s", strerror(errno));
+
+ parcEventQueue_SetWatermark(apiConnection->bev_api, PARCEventType_Write, MAX_API_QUEUE_BYTES, 0);
+ parcEventQueue_SetCallbacks(apiConnection->bev_api,
+ rtaApiConnection_Downcall_Read,
+ rtaApiConnection_WriteCallback,
+ rtaApiConnection_Downcall_Event,
+ (void *) connection);
+
+ parcEventQueue_Enable(apiConnection->bev_api, PARCEventType_Read | PARCEventType_Write);
+}
+
+RtaApiConnection *
+rtaApiConnection_Create(RtaConnection *connection)
+{
+ RtaApiConnection *apiConnection = parcMemory_AllocateAndClear(sizeof(RtaApiConnection));
+ assertNotNull(apiConnection, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(RtaApiConnection));
+
+ apiConnection->connection = rtaConnection_Copy(connection);
+ apiConnection->api_fd = rtaConnection_GetApiFd(connection);
+ apiConnection->transport_fd = rtaConnection_GetTransportFd(connection);
+ rtaApiConnection_SetupSocket(apiConnection, connection);
+
+ return apiConnection;
+}
+
+void
+rtaApiConnection_Destroy(RtaApiConnection **apiConnectionPtr)
+{
+ assertNotNull(apiConnectionPtr, "Parameter apiConnecitonPtr must be non-null");
+ assertNotNull(*apiConnectionPtr, "Parameter apiConnecitonPtr must dereference to non-null");
+ RtaApiConnection *apiConnection = *apiConnectionPtr;
+
+
+ // Send all the outbound messages up to the API. This at least gets them out
+ // of our output queue on to the API's socket.
+ parcEventQueue_Finished(apiConnection->bev_api, PARCEventType_Write);
+ rtaApiConnection_DrainApiConnection(apiConnection);
+
+ parcEventQueue_Destroy(&(apiConnection->bev_api));
+
+ rtaConnection_Destroy(&apiConnection->connection);
+
+ parcMemory_Deallocate((void **) &apiConnection);
+
+ *apiConnectionPtr = NULL;
+}
+
+static void
+rtaApiConnection_SendToApiAsDictionary(RtaApiConnection *apiConnection, TransportMessage *tm)
+{
+ CCNxMetaMessage *msg = ccnxMetaMessage_Acquire(transportMessage_GetDictionary(tm));
+ rtaApiConnection_WriteMessageToApi(apiConnection, msg);
+}
+
+static CCNxName *
+rtaApiConnection_GetNameFromTransportMessage(TransportMessage *tm)
+{
+ CCNxName *name = NULL;
+ CCNxTlvDictionary *dictionary = transportMessage_GetDictionary(tm);
+ switch (ccnxTlvDictionary_GetSchemaVersion(dictionary)) {
+ case CCNxTlvDictionary_SchemaVersion_V1:
+ name = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME);
+ break;
+
+ default:
+ break;
+ }
+ return name;
+}
+
+/**
+ * Writes the CCNxMessage inside the transport message up to the API.
+ * Its possible that if there's no space in the socket the write will block
+ * and return an error.
+ *
+ * @return true if written to API, false if not (most likely would block)
+ */
+bool
+rtaApiConnection_SendToApi(RtaApiConnection *apiConnection, TransportMessage *tm, RtaComponentStats *stats)
+{
+ assertNotNull(apiConnection, "Parameter apiConnection must be non-null");
+
+ if (DEBUG_OUTPUT) {
+ CCNxName *name = rtaApiConnection_GetNameFromTransportMessage(tm);
+ char *nameString = NULL;
+ if (name) {
+ nameString = ccnxName_ToString(name);
+ }
+
+ struct timeval delay = transportMessage_GetDelay(tm);
+ printf("%9" PRIu64 " %s putting transport msg %p to user fd %d delay %.6f name %s\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(apiConnection->connection))),
+ __func__,
+ (void *) tm,
+ apiConnection->api_fd,
+ delay.tv_sec + delay.tv_usec * 1E-6,
+ nameString);
+
+ if (nameString) {
+ parcMemory_Deallocate((void **) &nameString);
+ }
+ }
+
+ rtaApiConnection_SendToApiAsDictionary(apiConnection, tm);
+
+ rtaComponentStats_Increment(stats, STATS_UPCALL_OUT);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s conn %p fd_out %d state %p upcalls %u reads %u\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(apiConnection->connection))),
+ __func__,
+ (void *) apiConnection->connection,
+ apiConnection->transport_fd,
+ (void *) apiConnection,
+ api_upcall_writes,
+ rta_transport_reads);
+ }
+
+ return true;
+}
+
+void
+rtaApiConnection_BlockDown(RtaApiConnection *apiConnection)
+{
+ assertNotNull(apiConnection, "Parameter apiConnection must be non-null");
+ PARCEventType enabled_events = parcEventQueue_GetEnabled(apiConnection->bev_api);
+
+ // we only disable it and log it if it was active
+ if (enabled_events & PARCEventType_Read) {
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s connection %u blocked down, disable PARCEventType_Read\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(apiConnection->connection))),
+ __func__,
+ rtaConnection_GetConnectionId(apiConnection->connection));
+ }
+
+ parcEventQueue_Disable(apiConnection->bev_api, PARCEventType_Read);
+ }
+}
+
+void
+rtaApiConnection_UnblockDown(RtaApiConnection *apiConnection)
+{
+ assertNotNull(apiConnection, "Parameter apiConnection must be non-null");
+ PARCEventType enabled_events = parcEventQueue_GetEnabled(apiConnection->bev_api);
+
+ if (!(enabled_events & PARCEventType_Read)) {
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s connection %u unblocked down, enable PARCEventType_Read\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(apiConnection->connection))),
+ __func__,
+ rtaConnection_GetConnectionId(apiConnection->connection));
+ }
+ parcEventQueue_Enable(apiConnection->bev_api, PARCEventType_Read);
+ }
+}
+
+// ==========================================================================================
+// Internal implementation
+
+static void
+rtaApiConnection_WriteMessageToApi(RtaApiConnection *apiConnection, CCNxMetaMessage *msg)
+{
+ assertNotNull(msg, "Parameter msg must be non-null");
+
+ int error = parcEventQueue_Write(apiConnection->bev_api, &msg, sizeof(&msg));
+ assertTrue(error == 0,
+ "write to transport_fd %d write error: (%d) %s",
+ apiConnection->transport_fd, errno, strerror(errno));
+
+ // debugging tracking
+ api_upcall_writes++;
+}
+
+static void
+_rtaAPIConnection_ProcessCPIRequest(RtaConnection *conn, PARCJSON *json)
+{
+ // Is it a request type we know about?
+
+ switch (cpi_getCPIOperation2(json)) {
+ case CPI_PAUSE: {
+ RtaConnectionStateType oldstate = rtaConnection_GetState(conn);
+ if (oldstate == CONN_OPEN) {
+ rtaConnection_SetState(conn, CONN_PAUSED);
+ }
+ break;
+ }
+
+ default:
+ // do nothing, don't know about this message type
+ break;
+ }
+}
+
+static void
+connector_Api_ProcessCpiMessage(RtaConnection *conn, CCNxTlvDictionary *controlDictionary)
+{
+ if (ccnxControlFacade_IsCPI(controlDictionary)) {
+ PARCJSON *json = ccnxControlFacade_GetJson(controlDictionary);
+ switch (controlPlaneInterface_GetCPIMessageType(json)) {
+ case CPI_REQUEST: {
+ _rtaAPIConnection_ProcessCPIRequest(conn, json);
+ break;
+ }
+
+ case CPI_RESPONSE:
+ break;
+
+ case CPI_ACK:
+ break;
+
+ default:
+ assertTrue(0, "Got unknown CPI message type: %d", controlPlaneInterface_GetCPIMessageType(json));
+ }
+ }
+}
+
+static void
+rtaApiConnection_ProcessControlFromApi(RtaApiConnection *apiConnection, RtaProtocolStack *stack, CCNxTlvDictionary *controlDictionary)
+{
+ if (ccnxControlFacade_IsCPI(controlDictionary)) {
+ connector_Api_ProcessCpiMessage(apiConnection->connection, controlDictionary);
+ }
+}
+
+static void
+rtaApiConnection_Downcall_ProcessDictionary(RtaApiConnection *apiConnection, RtaProtocolStack *stack,
+ PARCEventQueue *queue_out, RtaComponentStats *stats, CCNxTlvDictionary *messageDictionary)
+{
+ // Look at the control message before checking for the connection closed
+ if (ccnxTlvDictionary_IsControl(messageDictionary)) {
+ rtaApiConnection_ProcessControlFromApi(apiConnection, stack, messageDictionary);
+ }
+
+ // In paused or closed state, we only pass control messages
+ if ((rtaConnection_GetState(apiConnection->connection) == CONN_OPEN) || (ccnxTlvDictionary_IsControl(messageDictionary))) {
+ TransportMessage *tm = transportMessage_CreateFromDictionary(messageDictionary);
+
+ // Set the auxiliary information to the message's connection
+ transportMessage_SetInfo(tm, rtaConnection_Copy(apiConnection->connection), rtaConnection_FreeFunc);
+
+ if (DEBUG_OUTPUT) {
+ CCNxName *name = NULL;
+ if (ccnxTlvDictionary_IsInterest(messageDictionary)) {
+ name = ccnxInterest_GetName(messageDictionary);
+ } else if (ccnxTlvDictionary_IsContentObject(messageDictionary)) {
+ name = ccnxContentObject_GetName(messageDictionary);
+ }
+
+ char *noname = "NONAME";
+ char *nameString = noname;
+ if (name) {
+ nameString = ccnxName_ToString(name);
+ }
+
+ printf("%9" PRIu64 " %s putting transport msg %p from user fd %d: %s\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(apiConnection->connection))),
+ __func__,
+ (void *) tm, apiConnection->api_fd,
+ nameString);
+
+ if (nameString != noname) {
+ parcMemory_Deallocate((void **) &nameString);
+ }
+
+ //ccnxTlvDictionary_Display(0, messageDictionary);
+ }
+
+ // send down the stack. If it fails, it destroys the message.
+ if (rtaComponent_PutMessage(queue_out, tm)) {
+ rtaComponentStats_Increment(stats, STATS_DOWNCALL_OUT);
+ }
+ }
+}
+
+static void
+rtaApiConnection_Downcall_ProcessMessage(RtaApiConnection *apiConnection, RtaProtocolStack *stack, PARCEventBuffer *eb_in,
+ PARCEventQueue *queue_out, RtaComponentStats *stats)
+{
+ api_downcall_reads++;
+ CCNxMetaMessage *msg;
+
+ int bytesRemoved = parcEventBuffer_Read(eb_in, &msg, sizeof(CCNxMetaMessage *));
+ assertTrue(bytesRemoved == sizeof(CCNxMetaMessage *),
+ "Error, did not remove an entire pointer, expected %zu got %d",
+ sizeof(CCNxMetaMessage *),
+ bytesRemoved);
+
+ rtaComponentStats_Increment(stats, STATS_DOWNCALL_IN);
+
+ // This will save its own reference to the messageDictionary
+ rtaApiConnection_Downcall_ProcessDictionary(apiConnection, stack, queue_out, stats, msg);
+
+ // At this point, the CCNxMetaMessage passed in by the application thread has been
+ // acquired rtaApiConnection_Downcall_ProcessDictionary(), so we can Release the reference we
+ // acquired in rtaTransport_Send().
+ ccnxMetaMessage_Release(&msg);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s conn %p total downcall reads in %" PRIu64 " out %" PRIu64 "\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(apiConnection->connection))),
+ __func__,
+ (void *) apiConnection->connection,
+ rtaComponentStats_Get(stats, STATS_DOWNCALL_IN),
+ rtaComponentStats_Get(stats, STATS_DOWNCALL_OUT));
+ }
+}
+
+
+/*
+ * Called by PARCEvent when there's a message to read from the API
+ * Read a message from the API.
+ * rtaConnectionVoid is the RtaConnection associated with the api descriptor
+ */
+static void
+rtaApiConnection_Downcall_Read(PARCEventQueue *bev, PARCEventType type, void *rtaConnectionVoid)
+{
+ RtaConnection *conn = (RtaConnection *) rtaConnectionVoid;
+
+ assertNotNull(rtaConnectionVoid, "Parameter must be a non-null void *");
+
+ RtaProtocolStack *stack = rtaConnection_GetStack(conn);
+ assertNotNull(stack, "rtaConnection_GetStack returned null");
+
+ RtaComponentStats *stats = rtaConnection_GetStats(conn, API_CONNECTOR);
+ assertNotNull(stats, "rtaConnection_GetStats returned null");
+
+ RtaApiConnection *apiConnection = rtaConnection_GetPrivateData(conn, API_CONNECTOR);
+ assertNotNull(apiConnection, "rtaConnection_GetPrivateData got null");
+
+ PARCEventBuffer *eb_in = parcEventBuffer_GetQueueBufferInput(bev);
+
+ PARCEventQueue *queue_out = rtaComponent_GetOutputQueue(conn, API_CONNECTOR, RTA_DOWN);
+ assertNotNull(queue_out, "component_GetOutputQueue returned null");
+
+ while (parcEventBuffer_GetLength(eb_in) >= sizeof(TransportMessage *)) {
+ rtaApiConnection_Downcall_ProcessMessage(apiConnection, stack, eb_in, queue_out, stats);
+ }
+ parcEventBuffer_Destroy(&eb_in);
+}
+
+/*
+ * This is used on the connection to the API out of the transport box
+ */
+static void
+rtaApiConnection_Downcall_Event(PARCEventQueue *bev, PARCEventQueueEventType events, void *ptr)
+{
+}
+
+/**
+ * Drains all the CCNxMessages off an event buffer and destroys them
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+drainBuffer(PARCEventBuffer *buffer, RtaConnection *conn)
+{
+ size_t length;
+
+ while ((length = parcEventBuffer_GetLength(buffer)) > 0) {
+ CCNxMetaMessage *msg;
+ ssize_t len;
+
+ len = parcEventBuffer_Read(buffer, &msg, sizeof(CCNxMetaMessage *));
+ assertTrue(len == sizeof(CCNxMetaMessage *),
+ "Removed incorrect length, expected %zu got %zd: (%d) %s",
+ sizeof(CCNxMetaMessage *),
+ len,
+ errno,
+ strerror(errno));
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s conn %p drained message %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ (void *) conn,
+ (void *) msg);
+ }
+ ccnxMetaMessage_Release(&msg);
+ }
+}
+
+/**
+ * Called on Destroy to clear our input buffer. This does not
+ * drain the output (to API) buffer, that is done by the RTA Framework
+ */
+static void
+rtaApiConnection_DrainApiConnection(RtaApiConnection *apiConnection)
+{
+ // drain and free the transport_fd
+ parcEventQueue_Disable(apiConnection->bev_api, PARCEventType_Read);
+
+ PARCEventBuffer *in = parcEventBuffer_GetQueueBufferInput(apiConnection->bev_api);
+ drainBuffer(in, apiConnection->connection);
+ parcEventBuffer_Destroy(&in);
+
+ // There may be some messages in the output buffer that
+ // have not actually been written to the kernel socket.
+ // Drain those too, as the API will never see them
+
+ if (DEBUG_OUTPUT) {
+ PARCEventBuffer *out = parcEventBuffer_GetQueueBufferOutput(apiConnection->bev_api);
+ printf("%9" PRIu64 " %s conn %p output buffer has %zu bytes\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(apiConnection->connection))),
+ __func__,
+ (void *) apiConnection->connection,
+ parcEventBuffer_GetLength(out));
+ parcEventBuffer_Destroy(&out);
+ }
+}
+
+/**
+ * Called by PARCEvent when we cross below the write watermark
+ */
+static void
+rtaApiConnection_WriteCallback(PARCEventQueue *queue, PARCEventType type, void *connVoid)
+{
+ // we dropped below the write watermark, unblock the connection in the UP direction
+ RtaConnection *conn = (RtaConnection *) connVoid;
+ if (rtaConnection_BlockedUp(conn)) {
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s connection %u output fell below watermark, unblocking UP\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(rtaConnection_GetStack(conn))),
+ __func__,
+ rtaConnection_GetConnectionId(conn));
+ }
+
+ rtaConnection_ClearBlockedUp(conn);
+ }
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/rta_ApiConnection.h b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/rta_ApiConnection.h
new file mode 100644
index 00000000..799c45e6
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/rta_ApiConnection.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 rta_ApiConnection.h
+ * @brief Implementation of the API connection
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef TransportRTA_rta_ApiConnection_h
+#define TransportRTA_rta_ApiConnection_h
+
+struct rta_api_connection;
+typedef struct rta_api_connection RtaApiConnection;
+
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+
+RtaApiConnection *rtaApiConnection_Create(RtaConnection *connection);
+void rtaApiConnection_Destroy(RtaApiConnection **rtaApiConnectionPtr);
+
+/**
+ * Sends a TransportMessage up to the API
+ *
+ * Decapsulates the ccnx message and sends it up to the API. It will destroy the TransportMessage wrapper.
+ *
+ * @param [in] apiConnection The API connection to write to
+ * @param [in] tm The transport message to send
+ * @param [in] stats The statistics counter to increment on success
+ *
+ * @return true Transport message written
+ * @return false Transport message not written (but still destroyed)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool rtaApiConnection_SendToApi(RtaApiConnection *apiConnection, TransportMessage *tm, RtaComponentStats *stats);
+
+/**
+ * Block data flow in the DOWN direction
+ *
+ * To block in the DOWN direction, we disable READ events on the API's buffer
+ *
+ * @param [in] apiConnection The API Connector's connection state
+ * @param [in] conn The RTA Connection
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaApiConnection_BlockDown(RtaApiConnection *apiConnection);
+
+/**
+ * Unblock data flow in the DOWN direction
+ *
+ * To unblock in the DOWN direction, we enable READ events on the API's buffer
+ *
+ * @param [in] apiConnection The API Connector's connection state
+ * @param [in] conn The RTA Connection
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaApiConnection_UnblockDown(RtaApiConnection *apiConnection);
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/CMakeLists.txt b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/CMakeLists.txt
new file mode 100644
index 00000000..85e4812f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/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_connector_Api
+ test_rta_ApiConnection
+ test_connector_Forwarder_Local
+ test_connector_Forwarder_Metis
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_connector_Api.c b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_connector_Api.c
new file mode 100644
index 00000000..409e075d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_connector_Api.c
@@ -0,0 +1,61 @@
+/*
+ * 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 "../connector_Api.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(connector_Api)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(connector_Api)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(connector_Api)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(connector_Api);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_connector_Forwarder_Local.c b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_connector_Forwarder_Local.c
new file mode 100644
index 00000000..014f4bbe
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_connector_Forwarder_Local.c
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ */
+
+
+#define DEBUG_OUTPUT 1
+#include "../connector_Forwarder_Local.c"
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+
+#include <ccnx/api/control/cpi_ControlMessage.h>
+#include <ccnx/api/control/controlPlaneInterface.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Framework_Commands.c>
+#include <ccnx/transport/transport_rta/core/rta_Framework_private.h>
+#include <ccnx/transport/transport_rta/config/config_All.h>
+#include <ccnx/transport/test_tools/bent_pipe.h>
+
+typedef struct test_data {
+ PARCRingBuffer1x1 *commandRingBuffer;
+ PARCNotifier *commandNotifier;
+ RtaFramework *framework;
+
+ int api_fds[2];
+ int listen_fd;
+ int rnd_fd;
+
+ int stackId;
+ RtaConnection *connectionUnderTest;
+
+ char bentpipe_LocalName[1024];
+ BentPipeState *bentpipe;
+ char keystoreName[1024];
+ char keystorePassword[1024];
+} TestData;
+
+static CCNxTransportConfig *
+_createParams(const char *local_name, const char *keystore_name, const char *keystore_passwd)
+{
+ assertNotNull(local_name, "Got null keystore name\n");
+ assertNotNull(keystore_name, "Got null keystore name\n");
+ assertNotNull(keystore_passwd, "Got null keystore passwd\n");
+
+ CCNxStackConfig *stackConfig = apiConnector_ProtocolStackConfig(
+ testingUpper_ProtocolStackConfig(
+ localForwarder_ProtocolStackConfig(
+ protocolStack_ComponentsConfigArgs(ccnxStackConfig_Create(),
+ apiConnector_GetName(),
+ testingUpper_GetName(),
+ localForwarder_GetName(), NULL))));
+
+ CCNxConnectionConfig *connConfig = apiConnector_ConnectionConfig(
+ testingUpper_ConnectionConfig(
+ tlvCodec_ConnectionConfig(
+ localForwarder_ConnectionConfig(
+ ccnxConnectionConfig_Create(), local_name))));
+
+ publicKeySigner_ConnectionConfig(connConfig, keystore_name, keystore_passwd);
+
+ CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig);
+ ccnxStackConfig_Release(&stackConfig);
+ return result;
+}
+
+static TestData *
+_commonSetup(void)
+{
+ parcSecurity_Init();
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ sprintf(data->bentpipe_LocalName, "/tmp/bentpipe_%d.sock", getpid());
+ data->bentpipe = bentpipe_Create(data->bentpipe_LocalName);
+ bentpipe_Start(data->bentpipe);
+
+ sprintf(data->keystoreName, "/tmp/keystore_%d.p12", getpid());
+ sprintf(data->keystorePassword, "23439429");
+
+ unlink(data->keystoreName);
+
+ bool success = parcPkcs12KeyStore_CreateFile(data->keystoreName, data->keystorePassword, "user", 1024, 30);
+ assertTrue(success, "parcPkcs12KeyStore_CreateFile() failed.");
+
+ data->commandRingBuffer = parcRingBuffer1x1_Create(128, NULL);
+ data->commandNotifier = parcNotifier_Create();
+ data->framework = rtaFramework_Create(data->commandRingBuffer, data->commandNotifier);
+
+ // Create a protocol stack and a connection to use
+ CCNxTransportConfig *params = _createParams(data->bentpipe_LocalName, data->keystoreName, data->keystorePassword);
+
+ data->stackId = 1;
+
+ RtaCommandCreateProtocolStack *createStack =
+ rtaCommandCreateProtocolStack_Create(data->stackId, ccnxTransportConfig_GetStackConfig(params));
+
+ _rtaFramework_ExecuteCreateStack(data->framework, createStack);
+ rtaCommandCreateProtocolStack_Release(&createStack);
+
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, data->api_fds);
+ RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(data->stackId, data->api_fds[0], data->api_fds[1],
+ ccnxConnectionConfig_GetJson(ccnxTransportConfig_GetConnectionConfig(params)));
+ _rtaFramework_ExecuteOpenConnection(data->framework, openConnection);
+ rtaCommandOpenConnection_Release(&openConnection);
+
+ ccnxTransportConfig_Destroy(&params);
+
+ // now poke in to the connection table to get the connection to test
+ data->connectionUnderTest = rtaConnectionTable_GetByApiFd(data->framework->connectionTable, data->api_fds[0]);
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ rtaFramework_Teardown(data->framework);
+
+ parcRingBuffer1x1_Release(&data->commandRingBuffer);
+ parcNotifier_Release(&data->commandNotifier);
+ rtaFramework_Destroy(&data->framework);
+
+ bentpipe_Stop(data->bentpipe);
+ bentpipe_Destroy(&data->bentpipe);
+ unlink(data->keystoreName);
+ parcMemory_Deallocate((void **) &data);
+ parcSecurity_Fini();
+}
+
+// =============================================================
+
+LONGBOW_TEST_RUNNER(connector_Forwarder_Local)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(connector_Forwarder_Local)
+{
+ 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(connector_Forwarder_Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+// ======================================================
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, connector_Fwd_Local_Init_Release);
+ LONGBOW_RUN_TEST_CASE(Local, connector_Fwd_Local_Cpi_Pause);
+}
+
+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, connector_Fwd_Local_Init_Release)
+{
+ // nothing to do, just checking that memory is in balance in teardown
+}
+
+/**
+ * Send a PAUSE CPI message to the forwarder. It should reflect
+ * back a CPI ACK
+ */
+LONGBOW_TEST_CASE(Local, connector_Fwd_Local_Cpi_Pause)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCJSON *controlPause = cpi_CreatePauseInputRequest();
+
+ CCNxTlvDictionary *controlDictionary = ccnxControlFacade_CreateCPI(controlPause);
+ TransportMessage *tm_in = transportMessage_CreateFromDictionary(controlDictionary);
+
+ uint64_t pause_seqnum = controlPlaneInterface_GetSequenceNumber(controlPause);
+ parcJSON_Release(&controlPause);
+ ccnxTlvDictionary_Release(&controlDictionary);
+
+ transportMessage_SetInfo(tm_in, rtaConnection_Copy(data->connectionUnderTest), (void (*)(void **))rtaConnection_Destroy);
+
+ PARCEventQueue *in = rtaProtocolStack_GetPutQueue(rtaConnection_GetStack(data->connectionUnderTest), TESTING_UPPER, RTA_DOWN);
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(rtaConnection_GetStack(data->connectionUnderTest), TESTING_UPPER, RTA_DOWN);
+
+ rtaComponent_PutMessage(in, tm_in);
+
+ // this will crank it though the forwarder and reflect back up to us
+ rtaFramework_NonThreadedStepCount(data->framework, 4);
+
+ // The first message out should be a CONNECTION_OPEN
+ TransportMessage *tm_out = rtaComponent_GetMessage(out);
+ transportMessage_Destroy(&tm_out);
+
+ tm_out = rtaComponent_GetMessage(out);
+
+ assertTrue(transportMessage_IsControl(tm_out), "got wrong type, not a control message");
+
+ CCNxControl *control = ccnxMetaMessage_GetControl(transportMessage_GetDictionary(tm_out));
+
+ assertTrue(ccnxControl_IsACK(control), "Expected ccnxControl_IsACK to be true.");
+
+ uint64_t _ack_original_seqnum = ccnxControl_GetAckOriginalSequenceNumber(control);
+
+ assertTrue(_ack_original_seqnum == pause_seqnum,
+ "Got wrong original message seqnum, expected %" PRIu64 " got %" PRIu64, pause_seqnum, _ack_original_seqnum);
+
+ transportMessage_Destroy(&tm_out);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(connector_Forwarder_Local);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_connector_Forwarder_Metis.c b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_connector_Forwarder_Metis.c
new file mode 100644
index 00000000..6fe9e3d2
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_connector_Forwarder_Metis.c
@@ -0,0 +1,1350 @@
+/*
+ * 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 will setup a server socket so the Metis connector can connect to it. We can
+ * then see the packets the connector thinks it is sending to Metis.
+ */
+
+#define DEBUG 1
+#include "../connector_Forwarder_Metis.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_Security.h>
+
+#include <ccnx/api/control/cpi_ControlFacade.h>
+#include <ccnx/api/control/controlPlaneInterface.h>
+#include <ccnx/api/control/cpi_Forwarding.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Framework_Commands.c>
+#include <ccnx/transport/transport_rta/core/rta_Framework_private.h>
+#include <ccnx/transport/transport_rta/config/config_All.h>
+
+#include <ccnx/common/codec/ccnxCodec_TlvPacket.h>
+#include <ccnx/transport/test_tools/traffic_tools.h>
+
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h>
+#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.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_crc32c.h>
+
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+
+// inet_pton
+#include <arpa/inet.h>
+
+#include <LongBow/unit-test.h>
+
+static char keystorename[1024];
+static const char keystorepass[] = "2398472983479234";
+
+#ifndef INPORT_ANY
+#define INPORT_ANY 0
+#endif
+
+typedef struct test_data {
+ PARCRingBuffer1x1 *commandRingBuffer;
+ PARCNotifier *commandNotifier;
+
+ // we will bind to a random port, this is what we end up binding to
+ // Its in host byte order
+ uint16_t metis_port;
+
+ // server_socket is a socket we listen to like the Metis forwarder, so
+ // we can see all the traffic that comes out the bottom of the connector.
+ int server_socket;
+
+ // when we accept a client on the server socket, this is his socket
+ int client_socket;
+
+ RtaFramework *framework;
+ CCNxTransportConfig *params;
+
+ char keystoreName[1024];
+ char keystorePassword[1024];
+} TestData;
+
+/*
+ * @function setup_server
+ * @abstract Bind to 127.0.0.1 on a random port, returns the socket and port
+ * @discussion
+ * <#Discussion#>
+ *
+ * @param portOutput is the port bound to in host byte order
+ * @return <#return#>
+ */
+static int
+_setup_server(uint16_t *portOutput)
+{
+ struct sockaddr_in address;
+
+ /* listen on 127.0.0.1 random port */
+ address.sin_family = PF_INET;
+ address.sin_port = INPORT_ANY;
+ inet_pton(AF_INET, "127.0.0.1", &(address.sin_addr));
+
+ int fd = socket(PF_INET, SOCK_STREAM, 0);
+ assertFalse(fd < 0, "error on bind: (%d) %s", errno, strerror(errno));
+
+ // Set non-blocking flag
+ int flags = fcntl(fd, F_GETFL, NULL);
+ assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno);
+ int failure = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+ assertFalse(failure, "fcntl failed to set file descriptor flags (%d)\n", errno);
+
+ failure = bind(fd, (struct sockaddr *) &address, sizeof(struct sockaddr_in));
+ assertFalse(failure, "error on bind: (%d) %s", errno, strerror(errno));
+
+ failure = listen(fd, 16);
+ assertFalse(failure, "error on listen: (%d) %s", errno, strerror(errno));
+
+ socklen_t x = sizeof(address);
+ failure = getsockname(fd, (struct sockaddr *) &address, &x);
+ assertFalse(failure, "error on getsockname: (%d) %s", errno, strerror(errno));
+
+ *portOutput = htons(address.sin_port);
+
+ printf("test server setup on port %d\n", *portOutput);
+ return fd;
+}
+
+static int
+_accept_client(int server_socket)
+{
+ socklen_t addrlen;
+ struct sockaddr_in address;
+ int client_socket;
+
+ addrlen = sizeof(struct sockaddr_in);
+ client_socket = accept(server_socket, (struct sockaddr *) &address, &addrlen);
+ assertFalse(client_socket < 0, "accept error: %s", strerror(errno));
+
+ printf("%s accepted client on socket %d\n", __func__, client_socket);
+ return client_socket;
+}
+
+static RtaConnection *
+_openConnection(TestData *data, int stack_id, int fds[2])
+{
+ RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(stack_id, fds[0], fds[1],
+ ccnxConnectionConfig_GetJson(ccnxTransportConfig_GetConnectionConfig(data->params)));
+ _rtaFramework_ExecuteOpenConnection(data->framework, openConnection);
+ rtaCommandOpenConnection_Release(&openConnection);
+
+ return rtaConnectionTable_GetByApiFd(data->framework->connectionTable, fds[0]);
+}
+
+static void
+_createStack(TestData *data, int stack_id)
+{
+ RtaCommandCreateProtocolStack *createStack =
+ rtaCommandCreateProtocolStack_Create(stack_id, ccnxTransportConfig_GetStackConfig(data->params));
+ _rtaFramework_ExecuteCreateStack(data->framework, createStack);
+ rtaCommandCreateProtocolStack_Release(&createStack);
+}
+
+static CCNxTransportConfig *
+_createParams(int port, const char *keystore_name, const char *keystore_passwd)
+{
+ CCNxStackConfig *stackConfig;
+ CCNxConnectionConfig *connConfig;
+
+ assertNotNull(keystore_name, "Got null keystore name\n");
+ assertNotNull(keystore_passwd, "Got null keystore passwd\n");
+
+ stackConfig = apiConnector_ProtocolStackConfig(
+ testingUpper_ProtocolStackConfig(
+ metisForwarder_ProtocolStackConfig(
+ protocolStack_ComponentsConfigArgs(ccnxStackConfig_Create(),
+ apiConnector_GetName(),
+ testingUpper_GetName(),
+ metisForwarder_GetName(), NULL))));
+
+ connConfig = apiConnector_ConnectionConfig(
+ testingUpper_ConnectionConfig(
+ metisForwarder_ConnectionConfig(
+ tlvCodec_ConnectionConfig(
+ ccnxConnectionConfig_Create()), port)));
+
+ publicKeySigner_ConnectionConfig(connConfig, keystore_name, keystore_passwd);
+
+ CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig);
+ ccnxStackConfig_Release(&stackConfig);
+ return result;
+}
+
+static TestData *
+_commonSetup(void)
+{
+ parcSecurity_Init();
+
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ memset(data, 0, sizeof(TestData));
+
+ data->server_socket = _setup_server(&data->metis_port);
+
+ // printf("%s listening on port %u\n", __func__, data->metis_port);
+
+ sprintf(data->keystoreName, "%s", keystorename);
+ sprintf(data->keystorePassword, keystorepass);
+
+ data->commandRingBuffer = parcRingBuffer1x1_Create(128, NULL);
+ data->commandNotifier = parcNotifier_Create();
+ data->framework = rtaFramework_Create(data->commandRingBuffer, data->commandNotifier);
+
+ data->params = _createParams(data->metis_port, data->keystoreName, keystorepass);
+ // we will always create stack #1 as the default stack
+ _createStack(data, 1);
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ if (data != NULL) {
+ if (data->server_socket > 0) {
+ close(data->server_socket);
+ }
+
+ if (data->client_socket > 0) {
+ close(data->client_socket);
+ }
+
+ ccnxTransportConfig_Destroy(&data->params);
+ rtaFramework_Teardown(data->framework);
+
+ parcRingBuffer1x1_Release(&data->commandRingBuffer);
+ parcNotifier_Release(&data->commandNotifier);
+ rtaFramework_Destroy(&data->framework);
+ parcMemory_Deallocate((void **) &data);
+ }
+ parcSecurity_Fini();
+}
+
+// ======================================================
+// helper functions
+
+/**
+ * Wait for a READ event on the specifid socket. Has a 1 second timeout.
+ *
+ * @return true if READ event
+ * @return false otherwise
+ */
+static bool
+_waitForSelect(int fd)
+{
+ fd_set readset;
+ FD_ZERO(&readset);
+ FD_SET(fd, &readset);
+ int result = select(fd + 1, &readset, NULL, NULL, &(struct timeval) { 1, 0 });
+ assertFalse(result < 0, "Error on select: (%d) %s", errno, strerror(errno));
+ assertFalse(result == 0, "Timeout waiting for connection attempt");
+ assertTrue(FD_ISSET(fd, &readset), "server_socket was not set by select");
+
+ return true;
+}
+
+
+
+static size_t
+_sendPacketToConnectorV1(int fd, size_t payloadLength)
+{
+ // Setup the header
+ uint8_t headerLength = 13;
+ uint16_t packetLength = payloadLength + headerLength;
+ uint8_t packetType = CCNxCodecSchemaV1Types_PacketType_Interest;
+
+ CCNxCodecSchemaV1FixedHeader hdr = { .version = 1, .packetType = packetType, .packetLength = htons(packetLength), .headerLength = headerLength };
+
+ // put header in packet and write the packet
+ uint8_t packet[1024];
+ memcpy(packet, &hdr, sizeof(hdr));
+
+ // write out exactly the number of bytes we need
+ size_t writeSize = packetLength;
+
+ ssize_t nwritten = write(fd, packet, writeSize);
+ assertTrue(nwritten == writeSize, "Wrong write size, expected %zu got %zd", writeSize, nwritten);
+ return writeSize;
+}
+
+static RtaConnection *
+setupConnectionAndClientSocket(TestData *data, int *apiSocketOuptut, int *clientSocketOutput)
+{
+ // Open a listener and accept the forwarders connection
+ int fds[2];
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, fds);
+ RtaConnection *conn = _openConnection(data, 1, fds);
+ assertNotNull(conn, "Got null connection opening on stack 1");
+
+ rtaFramework_NonThreadedStepCount(data->framework, 2);
+
+ // we should now see a connection request
+ _waitForSelect(data->server_socket);
+
+ // accept the client and set a 1 second read timeout on the socket
+ int client_fd = _accept_client(data->server_socket);
+ struct timeval readTimeout = { 1, 0 };
+ setsockopt(client_fd, SOL_SOCKET, SO_RCVTIMEO, (char *) &readTimeout, sizeof(readTimeout));
+
+ *apiSocketOuptut = fds[0];
+ *clientSocketOutput = client_fd;
+ return conn;
+}
+
+// throw away the first control message
+static void
+_throwAwayControlMessage(PARCEventQueue *out)
+{
+ TransportMessage *control_tm = rtaComponent_GetMessage(out);
+ assertNotNull(control_tm, "Did not receive a transport message out of the top of the connector");
+ assertTrue(transportMessage_IsControl(control_tm),
+ "transport message is not a control message")
+ {
+ ccnxTlvDictionary_Display(transportMessage_GetDictionary(control_tm), 0);
+ }
+ transportMessage_Destroy(&control_tm);
+}
+
+static void
+_testReadPacketV1(size_t extraBytes)
+{
+ const int REMOTE = 0;
+ const int STACK = 1;
+ int fds[2];
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, fds);
+
+ PARCEventScheduler *scheduler = parcEventScheduler_Create();
+ FwdMetisState *fwd_state = connector_Fwd_Metis_CreateConnectionState(scheduler);
+
+ // this replaces "_openSocket"
+ fwd_state->fd = fds[STACK];
+
+ _setupSocket(fwd_state);
+
+ // Setup the header
+ uint16_t packetLength = 24;
+ uint8_t headerLength = 13;
+ uint8_t packetType = CCNxCodecSchemaV1Types_PacketType_Interest;
+
+ CCNxCodecSchemaV1FixedHeader hdr = { .version = 1, .packetType = packetType, .packetLength = htons(packetLength), .headerLength = headerLength };
+
+ // put header in packet and write the packet
+ uint8_t packet[1024];
+ memcpy(packet, &hdr, sizeof(hdr));
+
+ // write out exactly the number of bytes we need
+ size_t firstWrite = packetLength;
+
+ ssize_t nwritten = write(fds[REMOTE], packet, firstWrite + extraBytes);
+ assertTrue(nwritten == firstWrite + extraBytes, "Wrong write size, expected %zu got %zd",
+ firstWrite + extraBytes, nwritten);
+
+ ReadReturnCode readCode = _readPacket(fwd_state);
+
+ assertTrue(readCode == ReadReturnCode_Finished, "readCode should be %d got %d", ReadReturnCode_Finished, readCode);
+
+ // should indicate there's nothing left to read of the header
+ assertTrue(fwd_state->nextMessage.remainingReadLength == 0, "Remaining length should be 0 got %zu", fwd_state->nextMessage.remainingReadLength);
+
+ // we should be at position "firstWrite" in the packet buffer
+ assertNotNull(fwd_state->nextMessage.packet, "Packet buffer is null");
+ assertTrue(parcBuffer_Position(fwd_state->nextMessage.packet) == firstWrite,
+ "Wrong position, expected %zu got %zu", firstWrite, parcBuffer_Position(fwd_state->nextMessage.packet));
+
+ // cleanup
+ _fwdMetisState_Release(&fwd_state);
+ parcEventScheduler_Destroy(&scheduler);
+ close(fds[REMOTE]);
+}
+
+
+
+static void
+_testReadFromMetisFromArray(TestData *data, size_t length, uint8_t buffer[length])
+{
+ // create our connection. This will become part of the RTA framework, so will be
+ // cleaned up in the teardown
+ int api_fd;
+ int client_fd;
+ RtaConnection *conn = setupConnectionAndClientSocket(data, &api_fd, &client_fd);
+
+ ssize_t nwritten = write(client_fd, buffer, length);
+ assertTrue(nwritten == length, "Wrong write size, expected %zu got %zd", length, nwritten);
+
+ FwdMetisState *fwd_state = (FwdMetisState *) rtaConnection_GetPrivateData(conn, FWD_METIS);;
+
+ _readFromMetis(fwd_state, conn);
+
+ // now crank the handle to pop those messages up the stack
+ rtaFramework_NonThreadedStepCount(data->framework, 5);
+
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(rtaConnection_GetStack(conn), TESTING_UPPER, RTA_DOWN);
+ _throwAwayControlMessage(out);
+
+ // verify the wire format is what we wrote
+ TransportMessage *test_tm = rtaComponent_GetMessage(out);
+ assertNotNull(test_tm, "Did not receive a transport message out of the top of the connector");
+
+ CCNxTlvDictionary *testDictionary = transportMessage_GetDictionary(test_tm);
+ PARCBuffer *writeFormat = ccnxWireFormatMessage_GetWireFormatBuffer(testDictionary);
+ assertNotNull(writeFormat,
+ "transport message does not have a wire format");
+
+ PARCBuffer *truth = parcBuffer_Wrap(buffer, length, 0, length);
+ assertTrue(parcBuffer_Equals(truth, writeFormat), "Wire format does not match expected")
+ {
+ printf("Expected:\n");
+ parcBuffer_Display(truth, 3);
+ printf("Received:\n");
+ parcBuffer_Display(writeFormat, 3);
+ }
+
+ parcBuffer_Release(&truth);
+ transportMessage_Destroy(&test_tm);
+}
+
+
+// ======================================================
+
+LONGBOW_TEST_RUNNER(connector_Forwarder_Metis)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+
+ LONGBOW_RUN_TEST_FIXTURE(UpDirectionV1);
+ LONGBOW_RUN_TEST_FIXTURE(DownDirectionV1);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(connector_Forwarder_Metis)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ snprintf(keystorename, 1024, "/tmp/keystore_%d.p12", getpid());
+
+ // init + fini here so there's no memory imbalance
+ parcSecurity_Init();
+ parcPkcs12KeyStore_CreateFile(keystorename, keystorepass, "ccnxuser", 1024, 365);
+ parcSecurity_Fini();
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(connector_Forwarder_Metis)
+{
+ unlink(keystorename);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ======================================================
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, connector_Fwd_Metis_Init_Release);
+ LONGBOW_RUN_TEST_CASE(Local, connector_Fwd_Metis_Opener_GoodPort);
+ LONGBOW_RUN_TEST_CASE(Local, _fwdMetisState_Release);
+ LONGBOW_RUN_TEST_CASE(Local, _readInEnvironmentConnectionSpecification);
+}
+
+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, connector_Fwd_Metis_Init_Release)
+{
+ // nothing to do, just checking that memory is in balance in teardown
+}
+
+/**
+ * Call the opener with the right port. We should see a connection attempt on
+ * the server socket and be able to accept it.
+ */
+LONGBOW_TEST_CASE(Local, connector_Fwd_Metis_Opener_GoodPort)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int fds[2];
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, fds);
+ RtaConnection *conn = _openConnection(data, 1, fds);
+ assertNotNull(conn, "Got null connection opening on stack 1");
+
+ rtaFramework_NonThreadedStepCount(data->framework, 2);
+
+ // we should now see a connection request
+ _waitForSelect(data->server_socket);
+
+ close(fds[1]);
+}
+
+/**
+ * Make sure everything is released and file descriptor is closed
+ */
+LONGBOW_TEST_CASE(Local, _fwdMetisState_Release)
+{
+ const int REMOTE = 0;
+ const int STACK = 1;
+ int fds[2];
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, fds);
+
+ PARCEventScheduler *scheduler = parcEventScheduler_Create();
+ FwdMetisState *fwd_state = connector_Fwd_Metis_CreateConnectionState(scheduler);
+
+ // this replaces "_openSocket"
+ fwd_state->fd = fds[STACK];
+
+ _setupSocket(fwd_state);
+
+
+ _fwdMetisState_Release(&fwd_state);
+ parcEventScheduler_Destroy(&scheduler);
+
+ // ensure that fds[STACK] is closed by _fwdMetisState_Release
+ uint8_t buffer[16];
+ ssize_t nread = recv(fds[STACK], buffer, 16, 0);
+ assertTrue(nread == -1 && errno == EBADF,
+ "read from closed socket %d should be EBADF, got return %zd and errno (%d) %s",
+ fds[STACK], nread, errno, strerror(errno));
+
+ close(fds[REMOTE]);
+}
+
+LONGBOW_TEST_CASE(Local, _readInEnvironmentConnectionSpecification)
+{
+ char *oldEnv = getenv(FORWARDER_CONNECTION_ENV);
+ setenv(FORWARDER_CONNECTION_ENV, "tcp://127.0.0.1:9999", 1);
+ struct sockaddr_in addr_in;
+ _readInEnvironmentConnectionSpecification(&addr_in);
+ assertTrue(addr_in.sin_port == htons(9999), "Port specification incorrectly parsed");
+ assertTrue(addr_in.sin_addr.s_addr == inet_addr("127.0.0.1"), "Address specification incorrectly parsed");;
+ if (oldEnv) {
+ setenv(FORWARDER_CONNECTION_ENV, oldEnv, 1);
+ } else {
+ unsetenv(FORWARDER_CONNECTION_ENV);
+ }
+}
+
+
+
+// ====================================================================
+
+
+LONGBOW_TEST_FIXTURE(UpDirectionV1)
+{
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readPacketHeader_ExactFit);
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readPacketHeader_TwoReads);
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _setupNextPacket);
+
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readPacket_PartialMessage);
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readPacket_ExactlyOneMessage);
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readPacket_MoreThanOneMessage);
+
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readFromMetis_ThreeMessages);
+
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readFromMetis_InterestV1);
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readFromMetis_ContentObjectV1);
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readFromMetis_ControlV1);
+
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readPacketHeader_Error);
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readPacketBody_Error);
+
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readPacketHeader_Closed);
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readPacketBody_Closed);
+ LONGBOW_RUN_TEST_CASE(UpDirectionV1, _readFromMetis_Closed);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(UpDirectionV1)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(UpDirectionV1)
+{
+ _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;
+}
+
+/**
+ * Put in exactly 8 bytes.
+ * This should return NULL, but will set nextMessageLength to be the right thing.
+ * Does not drain the buffer
+ */
+LONGBOW_TEST_CASE(UpDirectionV1, _readPacketHeader_ExactFit)
+{
+ const int REMOTE = 0;
+ const int STACK = 1;
+ int fds[2];
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, fds);
+
+ PARCEventScheduler *scheduler = parcEventScheduler_Create();
+ FwdMetisState *fwd_state = connector_Fwd_Metis_CreateConnectionState(scheduler);
+
+ // this replaces "_openSocket"
+ fwd_state->fd = fds[STACK];
+
+ _setupSocket(fwd_state);
+
+ // Setup the header
+ uint16_t packetLength = 24;
+ uint8_t headerLength = 13;
+ uint8_t packetType = CCNxCodecSchemaV1Types_PacketType_Interest;
+
+ CCNxCodecSchemaV1FixedHeader hdr = { .version = 1, .packetType = packetType, .packetLength = htons(packetLength), .headerLength = headerLength };
+
+ // put header in packet and write the packet
+ uint8_t packet[1024];
+ size_t bufferReadLength = sizeof(hdr);
+ memcpy(packet, &hdr, bufferReadLength);
+
+ // write out exactly the number of bytes we need
+ ssize_t nwritten = write(fds[REMOTE], packet, sizeof(CCNxCodecSchemaV1FixedHeader));
+ assertTrue(nwritten == sizeof(CCNxCodecSchemaV1FixedHeader), "Wrong write size, expected %zu got %zd",
+ sizeof(CCNxCodecSchemaV1FixedHeader), nwritten);
+
+ // test the function
+ ReadReturnCode readCode = _readPacketHeader(fwd_state);
+ assertTrue(readCode == ReadReturnCode_Finished, "readCode should be %d got %d", ReadReturnCode_Finished, readCode);
+ assertTrue(fwd_state->nextMessage.remainingReadLength == 0, "Remaining length should be 0 got %zu", fwd_state->nextMessage.remainingReadLength);
+
+ // other properties are tested as part of _setupNextPacket
+
+ // cleanup
+ _fwdMetisState_Release(&fwd_state);
+ parcEventScheduler_Destroy(&scheduler);
+ close(fds[REMOTE]);
+}
+
+/*
+ * Write the fixed header in two 4 byte writes
+ */
+LONGBOW_TEST_CASE(UpDirectionV1, _readPacketHeader_TwoReads)
+{
+ const int REMOTE = 0;
+ const int STACK = 1;
+ int fds[2];
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, fds);
+
+ PARCEventScheduler *scheduler = parcEventScheduler_Create();
+ FwdMetisState *fwd_state = connector_Fwd_Metis_CreateConnectionState(scheduler);
+
+ // this replaces "_openSocket"
+ fwd_state->fd = fds[STACK];
+
+ _setupSocket(fwd_state);
+
+ // Setup the header
+ uint16_t packetLength = 24;
+ uint8_t headerLength = 13;
+ uint8_t packetType = CCNxCodecSchemaV1Types_PacketType_Interest;
+
+ CCNxCodecSchemaV1FixedHeader hdr = {
+ .version = 1,
+ .packetType = packetType,
+ .packetLength = htons(packetLength),
+ .headerLength = headerLength
+ };
+
+ // put header in packet and write the packet
+ uint8_t packet[1024];
+ size_t bufferReadLength = sizeof(hdr);
+ memcpy(packet, &hdr, bufferReadLength);
+
+ // write out exactly the number of bytes we need
+ size_t firstWrite = 4;
+ size_t secondWrite = sizeof(CCNxCodecSchemaV1FixedHeader) - firstWrite;
+
+ ssize_t nwritten = write(fds[REMOTE], packet, firstWrite);
+ assertTrue(nwritten == firstWrite, "Wrong write size, expected %zu got %zd", firstWrite, nwritten);
+
+ ReadReturnCode readCode = _readPacketHeader(fwd_state);
+ assertTrue(readCode == ReadReturnCode_PartialRead, "readCode should be %d got %d", ReadReturnCode_PartialRead, readCode);
+
+ nwritten = write(fds[REMOTE], packet + firstWrite, secondWrite);
+ assertTrue(nwritten == secondWrite, "Wrong write size, expected %zu got %zd", secondWrite, nwritten);
+
+ readCode = _readPacketHeader(fwd_state);
+ assertTrue(readCode == ReadReturnCode_Finished, "readCode should be %d got %d", ReadReturnCode_Finished, readCode);
+
+ assertTrue(fwd_state->nextMessage.remainingReadLength == 0, "Remaining length should be 0 got %zu", fwd_state->nextMessage.remainingReadLength);
+
+ // other properties are tested as part of _setupNextPacket
+
+ // cleanup
+ _fwdMetisState_Release(&fwd_state);
+ parcEventScheduler_Destroy(&scheduler);
+ close(fds[REMOTE]);
+}
+
+LONGBOW_TEST_CASE(UpDirectionV1, _setupNextPacket)
+{
+ uint16_t packetLength = 24;
+ uint8_t headerLength = 13;
+ uint8_t packetType = CCNxCodecSchemaV1Types_PacketType_Interest;
+ uint8_t version = 1;
+ CCNxCodecSchemaV1FixedHeader hdr = { .version = version, .packetType = packetType, .packetLength = htons(packetLength), .headerLength = headerLength };
+
+ // setup fwd_state->nextMessage like we just read a header
+ PARCEventScheduler *scheduler = parcEventScheduler_Create();
+ FwdMetisState *fwd_state = connector_Fwd_Metis_CreateConnectionState(scheduler);
+ fwd_state->nextMessage.remainingReadLength = 0;
+ memcpy(&fwd_state->nextMessage.fixedHeader, &hdr, sizeof(hdr));
+
+ // this is the truth we will test against
+ size_t nextMessageLength = packetLength;
+
+ _setupNextPacket(fwd_state);
+
+ size_t allocatedLength = parcBuffer_Capacity(fwd_state->nextMessage.packet);
+ size_t position = parcBuffer_Position(fwd_state->nextMessage.packet);
+ parcBuffer_Flip(fwd_state->nextMessage.packet);
+ void *buffer = parcBuffer_Overlay(fwd_state->nextMessage.packet, 0);
+
+ assertTrue(fwd_state->nextMessage.length == nextMessageLength, "Wrong packet length, expected %zu got %zu", nextMessageLength, fwd_state->nextMessage.length);
+ assertTrue(fwd_state->nextMessage.packetType == packetType, "Wrong packetType, expected %u got %u", packetType, fwd_state->nextMessage.packetType);
+ assertTrue(fwd_state->nextMessage.version == version, "Wrong version, expected %u got %u", version, fwd_state->nextMessage.version);
+ assertTrue(allocatedLength == nextMessageLength, "Wrong packet buffer length, expected %zu got %zu", nextMessageLength, allocatedLength);
+
+ // and make sure the beginning of the buffer is the fixed header
+ assertTrue(position == sizeof(hdr), "Wrong write position, expected %zu got %zu", sizeof(hdr), position);
+ assertTrue(memcmp(buffer, &hdr, sizeof(hdr)) == 0, "Beginning of buffer not the fixed header");
+
+ // TODO: Finish me
+ _fwdMetisState_Release(&fwd_state);
+ parcEventScheduler_Destroy(&scheduler);
+}
+
+/**
+ * Write the fixed header plus part of the message body.
+ */
+LONGBOW_TEST_CASE(UpDirectionV1, _readPacket_PartialMessage)
+{
+ const int REMOTE = 0;
+ const int STACK = 1;
+ int fds[2];
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, fds);
+
+ PARCEventScheduler *scheduler = parcEventScheduler_Create();
+ FwdMetisState *fwd_state = connector_Fwd_Metis_CreateConnectionState(scheduler);
+
+ // this replaces "_openSocket"
+ fwd_state->fd = fds[STACK];
+
+ _setupSocket(fwd_state);
+
+ // Setup the header
+ uint16_t packetLength = 160;
+ uint8_t headerLength = 13;
+ uint8_t packetType = CCNxCodecSchemaV1Types_PacketType_Interest;
+ uint8_t version = 1;
+ CCNxCodecSchemaV1FixedHeader hdr = { .version = version, .packetType = packetType, .packetLength = htons(packetLength), .headerLength = headerLength };
+
+ // put header in packet and write the packet
+ uint8_t packet[1024];
+ memcpy(packet, &hdr, sizeof(hdr));
+
+ // write out exactly the number of bytes we need
+ size_t firstWrite = 100;
+
+ ssize_t nwritten = write(fds[REMOTE], packet, firstWrite);
+ assertTrue(nwritten == firstWrite, "Wrong write size, expected %zu got %zd", firstWrite, nwritten);
+
+ ReadReturnCode readCode = _readPacket(fwd_state);
+
+ assertTrue(readCode == ReadReturnCode_PartialRead, "return value should be %d got %d", ReadReturnCode_PartialRead, readCode);
+
+ // should indicate there's nothing left to read of the header
+ assertTrue(fwd_state->nextMessage.remainingReadLength == 0, "Remaining length should be 0 got %zu", fwd_state->nextMessage.remainingReadLength);
+
+ // we should be at position "firstWrite" in the packet buffer
+ assertNotNull(fwd_state->nextMessage.packet, "Packet buffer is null");
+ assertTrue(parcBuffer_Position(fwd_state->nextMessage.packet) == firstWrite,
+ "Wrong position, expected %zu got %zu", firstWrite, parcBuffer_Position(fwd_state->nextMessage.packet));
+
+ // cleanup
+ _fwdMetisState_Release(&fwd_state);
+ parcEventScheduler_Destroy(&scheduler);
+ close(fds[REMOTE]);
+}
+
+/**
+ * Write exactly one message
+ */
+LONGBOW_TEST_CASE(UpDirectionV1, _readPacket_ExactlyOneMessage)
+{
+ _testReadPacketV1(0);
+}
+
+/**
+ * Write more than one message.
+ */
+LONGBOW_TEST_CASE(UpDirectionV1, _readPacket_MoreThanOneMessage)
+{
+ _testReadPacketV1(100);
+}
+
+/**
+ * Make 3 messages pending on the read socket and make sure _readFromMetis delivers all
+ * 3 up the stack. _readFromMetis requires an RtaConnection, so we need a mock framework.
+ */
+LONGBOW_TEST_CASE(UpDirectionV1, _readFromMetis_ThreeMessages)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // create our connection. This will become part of the RTA framework, so will be
+ // cleaned up in the teardown
+ int api_fd;
+ int client_fd;
+ RtaConnection *conn = setupConnectionAndClientSocket(data, &api_fd, &client_fd);
+
+ // Write three wire format packets up the bottom of the connector
+ const int loopCount = 3;
+ size_t writeSizes[loopCount];
+
+ for (int i = 0; i < loopCount; i++) {
+ writeSizes[i] = _sendPacketToConnectorV1(client_fd, (i + 1) * 100);
+ }
+
+ FwdMetisState *fwd_state = (FwdMetisState *) rtaConnection_GetPrivateData(conn, FWD_METIS);;
+
+ _readFromMetis(fwd_state, conn);
+
+ // now crank the handle to pop those messages up the stack
+ rtaFramework_NonThreadedStepCount(data->framework, 5);
+
+ // now read the message out of the test component
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(rtaConnection_GetStack(conn), TESTING_UPPER, RTA_DOWN);
+
+ // throw away the first control message
+ _throwAwayControlMessage(out);
+
+ // Now read the actual messages we want to test
+ for (int i = 0; i < loopCount; i++) {
+ TransportMessage *test_tm = rtaComponent_GetMessage(out);
+ assertNotNull(test_tm, "Did not receive a transport message %d out of %d out of the top of the connector", i + 1, loopCount);
+
+ assertTrue(transportMessage_IsInterest(test_tm),
+ "second transport message is not an interest")
+ {
+ ccnxTlvDictionary_Display(transportMessage_GetDictionary(test_tm), 0);
+ }
+
+ // Make sure the transport message has the right properties
+ CCNxTlvDictionary *testDictionary = transportMessage_GetDictionary(test_tm);
+ PARCBuffer *writeFormat = ccnxWireFormatMessage_GetWireFormatBuffer(testDictionary);
+ assertNotNull(writeFormat,
+ "transport message does not have a wire format");
+
+ assertTrue(parcBuffer_Remaining(writeFormat) == writeSizes[i],
+ "Raw format message wrong length, expected %zu got %zu",
+ writeSizes[i],
+ parcBuffer_Remaining(writeFormat));
+
+ // cleanup
+ transportMessage_Destroy(&test_tm);
+ }
+
+ // no extra cleanup, done in teardown
+}
+
+LONGBOW_TEST_CASE(UpDirectionV1, _readFromMetis_InterestV1)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ _testReadFromMetisFromArray(data, sizeof(v1_interest_nameA), v1_interest_nameA);
+}
+
+LONGBOW_TEST_CASE(UpDirectionV1, _readFromMetis_ContentObjectV1)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ _testReadFromMetisFromArray(data, sizeof(v1_content_nameA_crc32c), v1_content_nameA_crc32c);
+}
+
+LONGBOW_TEST_CASE(UpDirectionV1, _readFromMetis_ControlV1)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ _testReadFromMetisFromArray(data, sizeof(v1_cpi_add_route_crc32c), v1_cpi_add_route_crc32c);
+}
+
+/*
+ * read from a closed socket
+ */
+LONGBOW_TEST_CASE(UpDirectionV1, _readPacketHeader_Closed)
+{
+ const int REMOTE = 0;
+ const int STACK = 1;
+ int fds[2];
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, fds);
+
+ PARCEventScheduler *scheduler = parcEventScheduler_Create();
+ FwdMetisState *fwd_state = connector_Fwd_Metis_CreateConnectionState(scheduler);
+ fwd_state->fd = fds[STACK];
+ _setupSocket(fwd_state);
+
+ // close remote side then try to write to it
+ close(fds[REMOTE]);
+
+ ReadReturnCode readCode = _readPacketHeader(fwd_state);
+
+ _fwdMetisState_Release(&fwd_state);
+ parcEventScheduler_Destroy(&scheduler);
+
+ assertTrue(readCode == ReadReturnCode_Closed, "Wrong return code, expected %d got %d", ReadReturnCode_Closed, readCode);
+}
+
+LONGBOW_TEST_CASE(UpDirectionV1, _readPacketBody_Closed)
+{
+ const int REMOTE = 0;
+ const int STACK = 1;
+ int fds[2];
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, fds);
+
+ PARCEventScheduler *scheduler = parcEventScheduler_Create();
+ FwdMetisState *fwd_state = connector_Fwd_Metis_CreateConnectionState(scheduler);
+ fwd_state->fd = fds[STACK];
+ _setupSocket(fwd_state);
+
+ ssize_t nwritten = write(fds[REMOTE], v1_interest_nameA, 8);
+ assertTrue(nwritten == 8, "Wrong write size, expected 8 got %zd", nwritten);
+
+ // read the header to setup the read of the body
+ ReadReturnCode readCode;
+
+ readCode = _readPacketHeader(fwd_state);
+ assertTrue(readCode == ReadReturnCode_Finished, "Did not read entire header");
+
+ // close remote side then try to write to it
+ close(fds[REMOTE]);
+
+ // now try 2nd read
+ readCode = _readPacketBody(fwd_state);
+
+ _fwdMetisState_Release(&fwd_state);
+ parcEventScheduler_Destroy(&scheduler);
+
+ assertTrue(readCode == ReadReturnCode_Closed, "Wrong return code, expected %d got %d", ReadReturnCode_Closed, readCode);
+}
+
+/*
+ * Set the socket to -1 to cause and error
+ */
+LONGBOW_TEST_CASE(UpDirectionV1, _readPacketHeader_Error)
+{
+ const int REMOTE = 0;
+ const int STACK = 1;
+ int fds[2];
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, fds);
+
+ PARCEventScheduler *scheduler = parcEventScheduler_Create();
+ FwdMetisState *fwd_state = connector_Fwd_Metis_CreateConnectionState(scheduler);
+ fwd_state->fd = fds[STACK];
+ _setupSocket(fwd_state);
+
+ fwd_state->fd = -1;
+
+ // close remote side then try to write to it
+
+ ReadReturnCode readCode = _readPacketHeader(fwd_state);
+
+ _fwdMetisState_Release(&fwd_state);
+ parcEventScheduler_Destroy(&scheduler);
+ close(fds[STACK]);
+ close(fds[REMOTE]);
+
+ assertTrue(readCode == ReadReturnCode_Error, "Wrong return code, expected %d got %d", ReadReturnCode_Error, readCode);
+}
+
+/*
+ * Set the socket to -1 to cause and error
+ */
+LONGBOW_TEST_CASE(UpDirectionV1, _readPacketBody_Error)
+{
+ const int REMOTE = 0;
+ const int STACK = 1;
+ int fds[2];
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, fds);
+
+ PARCEventScheduler *scheduler = parcEventScheduler_Create();
+ FwdMetisState *fwd_state = connector_Fwd_Metis_CreateConnectionState(scheduler);
+ fwd_state->fd = fds[STACK];
+ _setupSocket(fwd_state);
+
+ ssize_t nwritten = write(fds[REMOTE], v1_interest_nameA, 8);
+ assertTrue(nwritten == 8, "Wrong write size, expected 8 got %zd", nwritten);
+
+ // read the header to setup the read of the body
+ ReadReturnCode readCode;
+
+ readCode = _readPacketHeader(fwd_state);
+ assertTrue(readCode == ReadReturnCode_Finished, "Did not read entire header");
+
+ // invalidate to cause an error
+ fwd_state->fd = -1;
+
+ // now try 2nd read
+ readCode = _readPacketBody(fwd_state);
+
+ _fwdMetisState_Release(&fwd_state);
+ parcEventScheduler_Destroy(&scheduler);
+ close(fds[STACK]);
+ close(fds[REMOTE]);
+
+ assertTrue(readCode == ReadReturnCode_Error, "Wrong return code, expected %d got %d", ReadReturnCode_Error, readCode);
+}
+
+/*
+ * read from a closed socket.
+ * This should generate a Notify message that the connection is closed
+ */
+LONGBOW_TEST_CASE(UpDirectionV1, _readFromMetis_Closed)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // create our connection. This will become part of the RTA framework, so will be
+ // cleaned up in the teardown
+ int api_fd;
+ int client_fd;
+ RtaConnection *conn = setupConnectionAndClientSocket(data, &api_fd, &client_fd);
+ FwdMetisState *fwd_state = (FwdMetisState *) rtaConnection_GetPrivateData(conn, FWD_METIS);;
+
+ rtaFramework_NonThreadedStepCount(data->framework, 5);
+
+ close(client_fd);
+
+ _readFromMetis(fwd_state, conn);
+
+ // now crank the handle to pop those messages up the stack
+ rtaFramework_NonThreadedStepCount(data->framework, 5);
+
+ // now read the message out of the test component
+ PARCEventQueue *out = rtaProtocolStack_GetPutQueue(rtaConnection_GetStack(conn), TESTING_UPPER, RTA_DOWN);
+
+ // throw away the first control message
+ _throwAwayControlMessage(out);
+
+ TransportMessage *test_tm = rtaComponent_GetMessage(out);
+ assertNotNull(test_tm, "Did not receive a transport message out of the top of the connector");
+
+ assertTrue(transportMessage_IsControl(test_tm),
+ "second transport message is not a control")
+ {
+ ccnxTlvDictionary_Display(transportMessage_GetDictionary(test_tm), 0);
+ }
+
+ // Make sure the transport message has the right properties
+ CCNxTlvDictionary *testDictionary = transportMessage_GetDictionary(test_tm);
+ assertTrue(ccnxControlFacade_IsNotification(testDictionary), "Control message is not Notification")
+ {
+ ccnxTlvDictionary_Display(testDictionary, 3);
+ }
+
+ PARCJSON *json = ccnxControlFacade_GetJson(testDictionary);
+ NotifyStatus *notify = notifyStatus_ParseJSON(json);
+ assertTrue(notifyStatus_GetStatusCode(notify) == notifyStatusCode_CONNECTION_CLOSED,
+ "Wrong code, expected %d got %d",
+ notifyStatusCode_CONNECTION_CLOSED,
+ notifyStatus_GetStatusCode(notify));
+ notifyStatus_Release(&notify);
+
+ // verify other properties
+ assertFalse(fwd_state->isConnected, "Forwarder state should show connection closed");
+
+ // cleanup
+ transportMessage_Destroy(&test_tm);
+
+ // no extra cleanup, done in teardown
+}
+
+LONGBOW_TEST_FIXTURE(DownDirectionV1)
+{
+ LONGBOW_RUN_TEST_CASE(DownDirectionV1, _queueMessageToMetis);
+ LONGBOW_RUN_TEST_CASE(DownDirectionV1, _dequeueMessagesToMetis);
+ LONGBOW_RUN_TEST_CASE(DownDirectionV1, _dequeueMessagesToMetis_TwoWrites);
+ LONGBOW_RUN_TEST_CASE(DownDirectionV1, _dequeueMessagesToMetis_Closed);
+
+ LONGBOW_RUN_TEST_CASE(DownDirectionV1, connector_Fwd_Metis_Downcall_Read_Interst);
+ LONGBOW_RUN_TEST_CASE(DownDirectionV1, connector_Fwd_Metis_Downcall_Read_CPIRequest);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(DownDirectionV1)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(DownDirectionV1)
+{
+ _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;
+}
+
+/*
+ * _queueMessageToMetis postconditions:
+ * - increases the reference count to the wireFormat
+ * - adds the reference to fwd_output buffer
+ * - increments the debugging counter fwd_metis_references_queued
+ */
+LONGBOW_TEST_CASE(DownDirectionV1, _queueMessageToMetis)
+{
+ PARCEventScheduler *scheduler = parcEventScheduler_Create();
+ FwdMetisState *fwd_state = connector_Fwd_Metis_CreateConnectionState(scheduler);
+ PARCBuffer *wireFormat = parcBuffer_Wrap(v1_interest_nameA, sizeof(v1_interest_nameA), 0, sizeof(v1_interest_nameA));
+ size_t expectedRefCount = parcObject_GetReferenceCount(wireFormat);
+
+ _queueBufferMessageToMetis(wireFormat, fwd_state->metisOutputQueue);
+
+ assertTrue(parcObject_GetReferenceCount(wireFormat) == expectedRefCount,
+ "Did not get right ref count for wire format, expected %zu got %" PRIu64, expectedRefCount, parcObject_GetReferenceCount(wireFormat));
+ assertTrue(parcEventBuffer_GetLength(fwd_state->metisOutputQueue) == parcBuffer_Remaining(wireFormat),
+ "Wrong output buffer length, expected %zu got %zu", parcBuffer_Remaining(wireFormat), parcEventBuffer_GetLength(fwd_state->metisOutputQueue));
+
+ parcBuffer_Release(&wireFormat);
+ parcEventBuffer_Destroy(&fwd_state->metisOutputQueue);
+ _fwdMetisState_Release(&fwd_state);
+ parcEventScheduler_Destroy(&scheduler);
+}
+
+/*
+ * Dequeue a small message to metis, should all be written out.
+ */
+LONGBOW_TEST_CASE(DownDirectionV1, _dequeueMessagesToMetis)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int api_fd;
+ int client_fd;
+ RtaConnection *conn = setupConnectionAndClientSocket(data, &api_fd, &client_fd);
+
+ FwdMetisState *fwd_state = (FwdMetisState *) rtaConnection_GetPrivateData(conn, FWD_METIS);;
+
+ // Put data in the output queue
+ PARCBuffer *wireFormat = parcBuffer_Wrap(v1_interest_nameA, sizeof(v1_interest_nameA), 0, sizeof(v1_interest_nameA));
+ _queueBufferMessageToMetis(wireFormat, fwd_state->metisOutputQueue);
+
+ // write it out
+ _dequeueMessagesToMetis(fwd_state);
+ rtaFramework_NonThreadedStepCount(data->framework, 5);
+
+ // we should now be able to read it
+ bool readReady = _waitForSelect(client_fd);
+ assertTrue(readReady, "client socket %d not ready for read", client_fd);
+
+ uint8_t testArray[sizeof(v1_interest_nameA) + 1];
+ ssize_t nrecv = recv(client_fd, testArray, sizeof(testArray), 0);
+
+ assertTrue(nrecv == sizeof(v1_interest_nameA), "Wrong read length, expected %zu got %zd", sizeof(v1_interest_nameA), nrecv);
+ assertTrue(memcmp(testArray, v1_interest_nameA, sizeof(v1_interest_nameA)) == 0, "Read memory does not compare");
+ assertTrue(parcEventBuffer_GetLength(fwd_state->metisOutputQueue) == 0, "Metis output buffer not zero length, got %zu", parcEventBuffer_GetLength(fwd_state->metisOutputQueue));
+ parcEventBuffer_Destroy(&(fwd_state->metisOutputQueue));
+ parcBuffer_Release(&wireFormat);
+}
+
+/*
+ * Set the forwarder's send buffer small so it will take two writes to send the packet.
+ * This will test that when _dequeueMessagesToMetis cannot write the whole thing it will enable the
+ * write event and that metis will then trigger a second write when there's buffer space.
+ */
+LONGBOW_TEST_CASE(DownDirectionV1, _dequeueMessagesToMetis_TwoWrites)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int api_fd;
+ int client_fd;
+ RtaConnection *conn = setupConnectionAndClientSocket(data, &api_fd, &client_fd);
+
+ FwdMetisState *fwd_state = (FwdMetisState *) rtaConnection_GetPrivateData(conn, FWD_METIS);;
+
+ // set the send buffer
+ {
+ // make it slightly bigger than 1/2
+ const int sendBufferSize = sizeof(v1_interest_nameA) / 2 + 1;
+ int res = setsockopt(fwd_state->fd, SOL_SOCKET, SO_SNDBUF, &sendBufferSize, sizeof(int));
+ if (res < 0) {
+ if (DEBUG_OUTPUT) {
+ printf("%9c %s failed to set SO_SNDBUF to %d: (%d) %s\n",
+ ' ', __func__, sendBufferSize, errno, strerror(errno));
+ }
+ // This is a non-fatal error
+ }
+ }
+
+ // Put data in the output queue
+ PARCBuffer *wireFormat = parcBuffer_Wrap(v1_interest_nameA, sizeof(v1_interest_nameA), 0, sizeof(v1_interest_nameA));
+ _queueBufferMessageToMetis(wireFormat, fwd_state->metisOutputQueue);
+
+ // write it out
+ _dequeueMessagesToMetis(fwd_state);
+ rtaFramework_NonThreadedStepCount(data->framework, 5);
+
+ // we should now be able to read it
+ bool readReady = _waitForSelect(client_fd);
+ assertTrue(readReady, "client socket %d not ready for read", client_fd);
+
+ uint8_t testArray[sizeof(v1_interest_nameA) + 1];
+ ssize_t nrecv = recv(client_fd, testArray, sizeof(testArray), 0);
+
+ assertTrue(nrecv == sizeof(v1_interest_nameA), "Wrong read length, expected %zu got %zd", sizeof(v1_interest_nameA), nrecv);
+ assertTrue(memcmp(testArray, v1_interest_nameA, sizeof(v1_interest_nameA)) == 0, "Read memory does not compare");
+ assertTrue(parcEventBuffer_GetLength(fwd_state->metisOutputQueue) == 0, "Metis output buffer not zero length, got %zu", parcEventBuffer_GetLength(fwd_state->metisOutputQueue));
+ parcEventBuffer_Destroy(&(fwd_state->metisOutputQueue));
+ parcBuffer_Release(&wireFormat);
+}
+
+/*
+ * Dequeue a message to a closed socket
+ */
+LONGBOW_TEST_CASE(DownDirectionV1, _dequeueMessagesToMetis_Closed)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int api_fd;
+ int client_fd;
+ RtaConnection *conn = setupConnectionAndClientSocket(data, &api_fd, &client_fd);
+
+ FwdMetisState *fwd_state = (FwdMetisState *) rtaConnection_GetPrivateData(conn, FWD_METIS);;
+ PARCBuffer *wireFormat = parcBuffer_Wrap(v1_interest_nameA, sizeof(v1_interest_nameA), 0, sizeof(v1_interest_nameA));
+ _queueBufferMessageToMetis(wireFormat, fwd_state->metisOutputQueue);
+
+ // close remote side then try to write to it
+ close(client_fd);
+
+ _dequeueMessagesToMetis(fwd_state);
+ rtaFramework_NonThreadedStepCount(data->framework, 5);
+
+ parcEventBuffer_Destroy(&(fwd_state->metisOutputQueue));
+ parcBuffer_Release(&wireFormat);
+}
+
+/**
+ * Sends an Interest down the stack. We need to create an Interest and encode its TLV wire format,
+ * then send it down the stack and make sure we receive it on a client socket. We don't actually
+ * run Metis in this test.
+ */
+LONGBOW_TEST_CASE(DownDirectionV1, connector_Fwd_Metis_Downcall_Read_Interst)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // create our connection. This will become part of the RTA framework, so will be
+ // cleaned up in the teardown
+ int api_fd;
+ int client_fd;
+ RtaConnection *conn = setupConnectionAndClientSocket(data, &api_fd, &client_fd);
+ FwdMetisState *fwd_state = (FwdMetisState *) rtaConnection_GetPrivateData(conn, FWD_METIS);
+
+ // Create the interest with wire format and send it down the stack
+ TransportMessage *tm = trafficTools_CreateTransportMessageWithDictionaryInterest(conn, CCNxTlvDictionary_SchemaVersion_V1);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(transportMessage_GetDictionary(tm), NULL);
+
+ ccnxWireFormatMessage_PutIoVec(transportMessage_GetDictionary(tm), vec);
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+
+ // send it down the stack
+ PARCEventQueue *in = rtaProtocolStack_GetPutQueue(rtaConnection_GetStack(conn), TESTING_UPPER, RTA_DOWN);
+ rtaComponent_PutMessage(in, tm);
+ rtaFramework_NonThreadedStepCount(data->framework, 5);
+
+ bool readReady = _waitForSelect(client_fd);
+ assertTrue(readReady, "select did not indicate read ready");
+
+ // now read it from out listener. It has a read timeout so if we dont get it in a reasonable amount
+ // of time, read will return an error about the timeout
+
+ const size_t maxPacketLength = 1024;
+ uint8_t packet[maxPacketLength];
+
+ ssize_t readBytes = read(client_fd, packet, maxPacketLength);
+ assertFalse(readBytes < 0, "Got error on read: (%d) %s", errno, strerror(errno));
+
+ parcEventBuffer_Destroy(&(fwd_state->metisOutputQueue));
+ close(client_fd);
+}
+
+/**
+ * Send an AddRoute command down the stack. It does not need a wire format in the transport message, its
+ * the job of the forwarder to create the Metis-specific message.
+ */
+LONGBOW_TEST_CASE(DownDirectionV1, connector_Fwd_Metis_Downcall_Read_CPIRequest)
+{
+ testUnimplemented("No way to create a v1 CPI message yet");
+
+// TestData *data = longBowTestCase_GetClipBoardData(testCase);
+//
+// // create our connection. This will become part of the RTA framework, so will be
+// // cleaned up in the teardown
+// int api_fd;
+// int client_fd;
+// RtaConnection *conn = setupConnectionAndClientSocket(data, &api_fd, &client_fd);
+// FwdMetisState *fwd_state = (FwdMetisState *) rtaConnection_GetPrivateData(conn, FWD_METIS);
+//
+// // now make the control message
+// TransportMessage *tm = trafficTools_CreateTransportMessageWithDictionaryControl(conn, CCNxTlvDictionary_SchemaVersion_V1);
+// CCNxCodecNetworkBufferIoVec *vec = ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(transportMessage_GetDictionary(tm), NULL);
+// ccnxWireFormatFacade_PutIoVec(transportMessage_GetDictionary(tm), vec);
+// ccnxCodecNetworkBufferIoVec_Release(&vec);
+//
+// // send it down the stack
+// PARCEventQueue *in = rtaProtocolStack_GetPutQueue(rtaConnection_GetStack(conn), TESTING_UPPER, RTA_DOWN);
+// rtaComponent_PutMessage(in, tm);
+// rtaFramework_NonThreadedStepCount(data->framework, 5);
+//
+// // now read it from out listener. It has a read timeout so if we dont get it in a reasonable amount
+// // of time, read will return an error about the timeout
+//
+// const size_t maxPacketLength = 1024;
+// uint8_t packet[maxPacketLength];
+//
+// ssize_t readBytes = read(client_fd, packet, maxPacketLength);
+// assertFalse(readBytes < 0, "Got error on read: (%d) %s", errno, strerror(errno));
+// parcEventBuffer_Destroy(&(fwd_state->metisOutputQueue));
+}
+
+// ====================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(connector_Forwarder_Metis);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_rta_ApiConnection.c b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_rta_ApiConnection.c
new file mode 100644
index 00000000..b0e937cd
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/connectors/test/test_rta_ApiConnection.c
@@ -0,0 +1,278 @@
+/*
+ * 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.
+ */
+
+/**
+ * Create a non-threaded framework to test internal RTA functions
+ *
+ */
+#include "../rta_ApiConnection.c"
+
+#include <poll.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <ccnx/transport/transport_rta/config/config_All.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_Commands.c>
+
+#include <ccnx/transport/test_tools/traffic_tools.h>
+
+typedef struct test_data {
+ PARCRingBuffer1x1 *commandRingBuffer;
+ PARCNotifier *commandNotifier;
+ RtaFramework *framework;
+
+ int api_fds[2];
+ int stackId;
+
+ RtaProtocolStack *stack;
+ RtaConnection *connection;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->commandRingBuffer = parcRingBuffer1x1_Create(128, NULL);
+ data->commandNotifier = parcNotifier_Create();
+ data->framework = rtaFramework_Create(data->commandRingBuffer, data->commandNotifier);
+ assertNotNull(data->framework, "rtaFramework_Create returned null");
+
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+
+ apiConnector_ProtocolStackConfig(stackConfig);
+ testingLower_ProtocolStackConfig(stackConfig);
+ protocolStack_ComponentsConfigArgs(stackConfig, apiConnector_GetName(), testingLower_GetName(), NULL);
+
+ rtaFramework_NonThreadedStepCount(data->framework, 10);
+
+ // Create the protocol stack
+
+ data->stackId = 1;
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(data->stackId, stackConfig);
+ _rtaFramework_ExecuteCreateStack(data->framework, createStack);
+ rtaCommandCreateProtocolStack_Release(&createStack);
+
+ rtaFramework_NonThreadedStepCount(data->framework, 10);
+ data->stack = (rtaFramework_GetProtocolStackByStackId(data->framework, data->stackId))->stack;
+
+ // Create a connection in the stack
+
+ int error = socketpair(AF_UNIX, SOCK_STREAM, 0, data->api_fds);
+ assertFalse(error, "Error creating socket pair: (%d) %s", errno, strerror(errno));
+
+ CCNxConnectionConfig *connConfig = ccnxConnectionConfig_Create();
+ apiConnector_ConnectionConfig(connConfig);
+
+ tlvCodec_ConnectionConfig(connConfig);
+
+ testingLower_ConnectionConfig(connConfig);
+
+ RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(data->stackId, data->api_fds[PAIR_OTHER], data->api_fds[PAIR_TRANSPORT], ccnxConnectionConfig_GetJson(connConfig));
+ _rtaFramework_ExecuteOpenConnection(data->framework, openConnection);
+ rtaCommandOpenConnection_Release(&openConnection);
+
+ rtaFramework_NonThreadedStepCount(data->framework, 10);
+
+ data->connection = rtaConnectionTable_GetByApiFd(data->framework->connectionTable, data->api_fds[PAIR_OTHER]);
+
+ // cleanup
+
+ ccnxConnectionConfig_Destroy(&connConfig);
+ ccnxStackConfig_Release(&stackConfig);
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ rtaFramework_Teardown(data->framework);
+
+ parcRingBuffer1x1_Release(&data->commandRingBuffer);
+ parcNotifier_Release(&data->commandNotifier);
+ rtaFramework_Destroy(&data->framework);
+
+ close(data->api_fds[0]);
+ close(data->api_fds[1]);
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(rta_ApiConnection)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(rta_ApiConnection)
+{
+ 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_ApiConnection)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaApiConnection_BlockDown);
+ LONGBOW_RUN_TEST_CASE(Global, rtaApiConnection_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, rtaApiConnection_Create_Checks);
+ LONGBOW_RUN_TEST_CASE(Global, rtaApiConnection_Create_Check_ApiSocket);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaApiConnection_UnblockDown);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ printf("Finishing testcase %s\n", longBowTestCase_GetName(testCase));
+ _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, rtaApiConnection_SendToApi)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaApiConnection *apiConnection = rtaConnection_GetPrivateData(data->connection, API_CONNECTOR);
+
+ TransportMessage *tm = trafficTools_CreateTransportMessageWithDictionaryInterest(data->connection, CCNxTlvDictionary_SchemaVersion_V1);
+
+ RtaComponentStats *stats = rtaConnection_GetStats(data->connection, API_CONNECTOR);
+ rtaApiConnection_SendToApi(apiConnection, tm, stats);
+ rtaFramework_NonThreadedStepCount(data->framework, 10);
+
+ // Let the dispatcher run
+ struct pollfd pfd = { .fd = data->api_fds[PAIR_OTHER], .events = POLLIN, .revents = 0 };
+ int millisecondTimeout = 1000;
+
+ int pollvalue = poll(&pfd, 1, millisecondTimeout);
+ assertTrue(pollvalue == 1, "Did not get an event from the API's side of the socket");
+
+ CCNxMetaMessage *testMessage;
+ ssize_t bytesRead = read(data->api_fds[PAIR_OTHER], &testMessage, sizeof(testMessage));
+ assertTrue(bytesRead == sizeof(testMessage), "Wrong read size, got %zd expected %zd: (%d) %s",
+ bytesRead, sizeof(testMessage),
+ errno, strerror(errno));
+ assertNotNull(testMessage, "Message read is NULL");
+
+
+ assertTrue(testMessage == transportMessage_GetDictionary(tm),
+ "Got wrong raw message, got %p expected %p",
+ (void *) testMessage, (void *) transportMessage_GetDictionary(tm));
+
+ ccnxMetaMessage_Release(&testMessage);
+ transportMessage_Destroy(&tm);
+}
+
+LONGBOW_TEST_CASE(Global, rtaApiConnection_BlockDown)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaApiConnection *apiConnection = rtaApiConnection_Create(data->connection);
+
+ // make sure we're startined unblocked
+ short enabled = parcEventQueue_GetEnabled(apiConnection->bev_api);
+ assertTrue(enabled & PARCEventType_Read, "PARCEventType_Read is not enabled on a new Api Connector: enabled = %04X", enabled);
+
+ rtaApiConnection_BlockDown(apiConnection);
+ enabled = parcEventQueue_GetEnabled(apiConnection->bev_api);
+ assertFalse(enabled & PARCEventType_Read, "PARCEventType_Read is still enabled after caling BlockDown: enabled = %04X", enabled);
+
+ rtaApiConnection_Destroy(&apiConnection);
+}
+
+LONGBOW_TEST_CASE(Global, rtaApiConnection_Create_Destroy)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ uint32_t beforeBalance = parcMemory_Outstanding();
+ RtaApiConnection *apiConnection = rtaApiConnection_Create(data->connection);
+ assertNotNull(apiConnection, "Got null API connection");
+
+ rtaApiConnection_Destroy(&apiConnection);
+ assertNull(apiConnection, "Destroy did not null apiConnection");
+ uint32_t afterBalance = parcMemory_Outstanding();
+ assertTrue(beforeBalance == afterBalance, "Memory imbalance: %d", (int) (afterBalance - beforeBalance));
+}
+
+LONGBOW_TEST_CASE(Global, rtaApiConnection_Create_Checks)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ RtaApiConnection *apiConnection = rtaApiConnection_Create(data->connection);
+ assertTrue(apiConnection->api_fd == rtaConnection_GetApiFd(data->connection),
+ "Wrong api fd, got %d expected %d",
+ apiConnection->api_fd, rtaConnection_GetApiFd(data->connection));
+
+ assertTrue(apiConnection->transport_fd == rtaConnection_GetTransportFd(data->connection),
+ "Wrong api fd, got %d expected %d",
+ apiConnection->transport_fd, rtaConnection_GetTransportFd(data->connection));
+
+ assertTrue(apiConnection->connection == data->connection,
+ "Wrong connection, got %p expected %p",
+ (void *) apiConnection->connection,
+ (void *) data->connection);
+
+ rtaApiConnection_Destroy(&apiConnection);
+}
+
+LONGBOW_TEST_CASE(Global, rtaApiConnection_Create_Check_ApiSocket)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaApiConnection *apiConnection = rtaApiConnection_Create(data->connection);
+
+ assertNotNull(apiConnection->bev_api, "API socket event null");
+
+ rtaApiConnection_Destroy(&apiConnection);
+}
+
+LONGBOW_TEST_CASE(Global, rtaApiConnection_UnblockDown)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaApiConnection *apiConnection = rtaApiConnection_Create(data->connection);
+
+ rtaApiConnection_BlockDown(apiConnection);
+ // we know from previous test that this puts the apiConnector in blocked state
+
+ rtaApiConnection_UnblockDown(apiConnection);
+ short enabled = parcEventQueue_GetEnabled(apiConnection->bev_api);
+ assertTrue(enabled & PARCEventType_Read, "PARCEventType_Read is not enabled after caling UnlockDown: enabled = %04X", enabled);
+
+ rtaApiConnection_Destroy(&apiConnection);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_ApiConnection);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/components.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/components.h
new file mode 100644
index 00000000..1a07bcf3
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/components.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+//
+// components.h
+// Libccnx
+//
+
+
+#ifndef Libccnx_components_h
+#define Libccnx_components_h
+
+// Every component in the system must be defined here
+// These must correspond to array indicies.
+typedef enum {
+ API_CONNECTOR = 0,
+ FC_NONE = 1,
+ FC_VEGAS = 2,
+ FC_PIPELINE = 3,
+ // vacant = 4,
+ // vacant = 5,
+ // vacant = 6,
+ CODEC_NONE = 7,
+ CODEC_UNSPEC = 8,
+ CODEC_TLV = 9,
+ // vacant = 10,
+ // vacant = 11,
+ FWD_NONE = 12,
+ FWD_LOCAL = 13,
+ // vacant = 14,
+ // vacant = 15,
+ TESTING_UPPER = 16,
+ TESTING_LOWER = 17,
+ FWD_METIS = 19,
+ LAST_COMPONENT = 20, // MUST ALWAYS BE LAST
+ UNKNOWN_COMPONENT // MUST BE VERY LAST
+} RtaComponents;
+
+
+// This is defied in rta_ProtocolStack.c and should be kept
+// in sync with RtaComponents
+extern const char *RtaComponentNames[LAST_COMPONENT];
+
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta.h
new file mode 100644
index 00000000..75b53950
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta.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.
+ */
+
+//
+// rta.h
+// Libccnx
+//
+//
+
+#ifndef Libccnx_rta_h
+#define Libccnx_rta_h
+
+#include "rta_Transport.h"
+#include "rta_ProtocolStack.h"
+#include "rta_Connection.h"
+#include "rta_Component.h"
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Component.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Component.c
new file mode 100644
index 00000000..4be0c085
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Component.c
@@ -0,0 +1,127 @@
+/*
+ * 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 <parc/algol/parc_EventBuffer.h>
+
+#include <ccnx/transport/common/transport_Message.h>
+#include <ccnx/transport/transport_rta/rta_Transport.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+
+
+#ifndef DEBUG_OUTPUT
+#define DEBUG_OUTPUT 0
+#endif
+
+PARCEventQueue *
+rtaComponent_GetOutputQueue(RtaConnection *conn,
+ RtaComponents component,
+ RtaDirection direction)
+{
+ RtaProtocolStack *stack;
+
+ assertNotNull(conn, "called with null connection\n");
+
+ stack = rtaConnection_GetStack(conn);
+ assertNotNull(stack, "resolved null stack\n");
+
+ return rtaProtocolStack_GetPutQueue(stack, component, direction);
+}
+
+int
+rtaComponent_PutMessage(PARCEventQueue *queue, TransportMessage *tm)
+{
+ RtaConnection *conn = rtaConnection_GetFromTransport(tm);
+ assertNotNull(conn, "Got null connection from transport message\n");
+
+ if (rtaConnection_GetState(conn) != CONN_CLOSED) {
+ PARCEventBuffer *out = parcEventBuffer_GetQueueBufferOutput(queue);
+ int res;
+
+ rtaConnection_IncrementMessagesInQueue(conn);
+
+ if (DEBUG_OUTPUT) {
+ printf("%s queue %-12s tm %p\n",
+ __func__,
+ rtaProtocolStack_GetQueueName(rtaConnection_GetStack(conn), queue),
+ (void *) tm);
+ }
+
+ res = parcEventBuffer_Append(out, (void *) &tm, sizeof(&tm));
+ assertTrue(res == 0, "%s parcEventBuffer_Append returned error\n", __func__);
+ parcEventBuffer_Destroy(&out);
+ return 1;
+ } else {
+ // drop
+ transportMessage_Destroy(&tm);
+
+ return 0;
+ }
+}
+
+TransportMessage *
+rtaComponent_GetMessage(PARCEventQueue *queue)
+{
+ PARCEventBuffer *in = parcEventBuffer_GetQueueBufferInput(queue);
+
+ while (parcEventBuffer_GetLength(in) >= sizeof(TransportMessage *)) {
+ ssize_t len;
+ TransportMessage *tm;
+ RtaConnection *conn;
+
+ len = parcEventBuffer_Read(in, (void *) &tm, sizeof(&tm));
+
+ assertTrue(len == sizeof(TransportMessage *),
+ "parcEventBuffer_Read returned error");
+
+ // Is the transport message for an open connection?
+ conn = rtaConnection_GetFromTransport(tm);
+ assertNotNull(conn, "%s GetInfo returnd null connection\n", __func__);
+
+ if (DEBUG_OUTPUT) {
+ printf("%s queue %-12s tm %p\n",
+ __func__,
+ rtaProtocolStack_GetQueueName(rtaConnection_GetStack(conn), queue),
+ (void *) tm);
+ }
+
+ (void) rtaConnection_DecrementMessagesInQueue(conn);
+
+ if (rtaConnection_GetState(conn) != CONN_CLOSED) {
+ parcEventBuffer_Destroy(&in);
+ return tm;
+ }
+
+ // it's a closed connection
+
+ if (DEBUG_OUTPUT) {
+ printf("%s clearing connection %p reference in transport\n",
+ __func__, (void *) conn);
+ }
+ //drop
+ transportMessage_Destroy(&tm);
+ }
+
+ parcEventBuffer_Destroy(&in);
+ return NULL;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Component.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Component.h
new file mode 100644
index 00000000..24efa6aa
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Component.h
@@ -0,0 +1,258 @@
+/*
+ * 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_Component.h
+ * @brief <#Brief Description#>
+ *
+ * A Component is a functional block within a protocol stack. It exists
+ * between the API Connector (at the top) and the Forwarder Connector
+ * (at the bottom). All components have a similar interface. The only
+ * slight variation is that components betwen the Forwarder Connector
+ * and the Codec deal in "wire" message formats, while components above
+ * the connector deal with "parsed" (CCNxMessage) formats.
+ *
+ * To write a component, follow these procedures:
+ * 1) add your component's name to components.h enum. This is the
+ * symbolic name you will use for it in the code. We'll call
+ * it PROTO_WIZ.
+ * 2) Copy a skeleton, such as component_Verifier.h for your header.
+ * Let's call it component_Wizard.h. Inside the header, you'll
+ * define the "operations" structure that's exported to the system.
+ * @code{.c}
+ **#ifndef Libccnx_component_wizard_h
+ **#define Libccnx_component_wizard_h
+ *
+ * // Function structs for component variations
+ * extern ComponentOperations proto_wizard_ops;
+ *
+ **#endif
+ * @endcode
+ *
+ * 3) Copy a skeleton, like component_Verifier_Null.c, for your
+ * implementation. Let's call it component_Wizard.c. Inside
+ * you must:
+ * a) instantiate proto_wizard_ops:
+ * @code{.c}
+ * static int component_Wizard_Init(ProtocolStack *stack);
+ * static int component_Wizard_Opener(RtaConnection *conn);
+ * static void component_Wizard_Upcall_Read(PARCEventQueue *, void *conn);
+ * static void component_Wizard_Downcall_Read(PARCEventQueue *, void *conn);
+ * static int component_Wizard_Closer(RtaConnection *conn);
+ * static int component_Wizard_Release(ProtocolStack *stack);
+ *
+ * ComponentOperations verify_null_ops = {
+ * component_Wizard_Init,
+ * component_Wizard_Opener,
+ * component_Wizard_Upcall_Read,
+ * NULL,
+ * component_Wizard_Downcall_Read,
+ * NULL,
+ * component_Wizard_Closer,
+ * component_Wizard_Release
+ * };
+ * @endcode
+ *
+ * These define the interface your component exposes to the stack
+ * Init: called once on stack creation
+ * Open: called once per connection Open
+ * UpcallRead: Called when the "upward" buffer has something to read
+ * DowncallRead: Called when the "downward" buffer has something to read
+ * Closer: called once per connection Close
+ * Release: called on protocol stack destruction.
+ *
+ * Optionally, you may include UpcallEvents and DowncallEvents, but
+ * in general those are not useful.
+ *
+ * Any of the function pointers in the "ops" may be NULL.
+ *
+ * b) Implement your Init. If you need to create a stack-wide data structure
+ * to track state, you would do something like this, which allocates
+ * memory and sticks it away in component-specific storage in the stack.
+ * Notice that protocolStack_SetPrivateData takes our protocol's name
+ * PROTO_WIZ as a parameter.
+ *
+ * @code{.c}
+ * static int
+ * component_Wizard_Init(ProtocolStack *stack)
+ * {
+ * struct mydata *data = mydata_Create();
+ * protocolStack_SetPrivateData(stack, PROTO_WIZ, data);
+ * return 0;
+ * }
+ * @endcode
+ *
+ * c) Implement your Opener. You will very likely want to keep per-connection
+ * state. This follows a similar method to the Init, but in a connection.
+ * We squirl away the connection-specific data similarly to the stack-wide
+ * data. In addition, it's good practice to fetch your component's Stats
+ * for the connection and increment the OPENS counter for a successful open.
+ *
+ * @code{.c}
+ * static int
+ * component_Wizard_Opener(RtaConnection *connection)
+ * {
+ * ComponentStats *stats;
+ * struct myState *mystate;
+ *
+ * parcMemory_AlocateAndClear(&mystate, sizeof(void *), sizeof(struct api_conn_state));
+ * rtaConnection_SetPrivateData(connection, PROTO_WIZ, mystate);
+ *
+ * stats = rtaConnection_GetStats(connection, PROTO_WIZ);
+ * stats_Increment(stats, STATS_OPENS);
+ * return 0;
+ * }
+ * @endcode
+ *
+ * d) Implement your Close and Release. These perform the inverse
+ * of the Open and Init. They should fetch your private data, if
+ * any, and free it:
+ * @code{.c}
+ * static int
+ * component_Wizard_Closer(RtaConnection *conn)
+ * {
+ * ComponentStats *stats = rtaConnection_GetStats(conn, PROTO_WIZ);
+ * struct myState *mystate = rtaConnection_GetPrivateData(conn, PROTO_WIZ);
+ *
+ * stats_Increment(stats, STATS_CLOSES);
+ * myState_Destroy(&mystate);
+ * return 0;
+ * }
+ *
+ * static int
+ * component_Wizard_Release(ProtocolStack *stack)
+ * {
+ * ComponentStats *stats = protocoLStack_GetStats(stack, PROTO_WIZ);
+ * struct myData *mydata = protocolStack_GetPrivateData(stack, PROTO_WIZ);
+ *
+ * stats_Increment(stats, STATS_CLOSES);
+ * myData_Destroy(&mydata);
+ * return 0;
+ * }
+ * @endcode
+ *
+ * d) Implement your Read handlers. They are similar for the upcall
+ * and downcall handlers. The main issue to be aware of is that
+ * you must *drain* the queue on each call. The callback is edge
+ * triggered.
+ *
+ * Below we show an example of the Upcall read callback, which means
+ * there is data from below travelling up the stack. Therefore, we
+ * retrieve the RTA_UP output queue to pass messages up the stack.
+ * The while() loop is what drains the queue.
+ *
+ * Note also that "ptr" is a pointer to the ProtocolStack that owns
+ * connecition (what your Init was called with). The Connection information
+ * rides inside the transport message, and is retrieved with a call
+ * to transportMessage_GetInfo().
+ *
+ * @code{.c}
+ * static void
+ * component_Wizard_Upcall_Read(PARCEventQueue *in, PARCEvent_EventType event, void *ptr)
+ * {
+ * ProtocolStack *stack = (ProtocolStack *) ptr;
+ * PARCEventQueue *out = protocoStack_GetPutQueue(stack, PROTO_WIZ, RTA_UP);
+ * TransportMessage *tm;
+ *
+ * while( (tm = rtaComponent_GetMessage(in)) != NULL )
+ * {
+ * RtaConnection *conn = transportMessage_GetInfo(tm);
+ * ComponentStats *stats = rtaConnection_GetStats(conn, PROTO_WIZ);
+ * CCNxMessage *msg = TransportMessage_GetCcnxMessage(tm);
+ *
+ * stats_Increment(stats, STATS_UPCALL_IN);
+ *
+ * // do something with the CCNxMessage
+ *
+ * if( rtaComponent_PutMessage(out, tm) )
+ * stats_Increment(stats, STATS_UPCALL_OUT);
+ * }
+ * }
+ * @endcode
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+/**
+ */
+
+#ifndef Libccnx_rta_component_h
+#define Libccnx_rta_component_h
+
+#include "components.h"
+#include "rta_ComponentQueue.h"
+#include "rta_ComponentStats.h"
+
+/**
+ * Init: one time initialization on first instantiation (0 success, -1 failure)
+ * Open: Per connection open, returns valid descriptor or -1 on failure
+ * upcallRead: Callback when one or more messages are available
+ * downcallRead: Callback when one or more messages are available.
+ * xEvent: Called for events on the queue
+ * Close: Per connection close
+ * Release: One time release of state when whole stack taken down
+ * stateChagne: Called when there is a state change related to the connection
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef struct {
+ int (*init)(RtaProtocolStack *stack);
+ int (*open)(RtaConnection *conn);
+ void (*upcallRead)(PARCEventQueue *queue, PARCEventType events, void *stack);
+ void (*upcallEvent)(PARCEventQueue *queue, PARCEventQueueEventType events, void *stack);
+ void (*downcallRead)(PARCEventQueue *queue, PARCEventType events, void *stack);
+ void (*downcallEvent)(PARCEventQueue *queue, PARCEventQueueEventType events, void *stack);
+ int (*close)(RtaConnection *conn);
+ int (*release)(RtaProtocolStack *stack);
+ void (*stateChange)(RtaConnection *conn);
+} RtaComponentOperations;
+
+extern PARCEventQueue *rtaComponent_GetOutputQueue(RtaConnection *conn,
+ RtaComponents component,
+ RtaDirection direction);
+
+/**
+ * Send a message between components. The API connector and Forwarder connector
+ * must set the connection information in the transport message with
+ * rtaConnection_SetInTransport().
+ *
+ * returns 1 on success, 0 on failure
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+extern int rtaComponent_PutMessage(PARCEventQueue *queue, TransportMessage *tm);
+
+/**
+ * Fetch a message from the queue. Will return NULL if no message
+ * is available.
+ *
+ * As a side effect, it will drain message on a closed connection.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+extern TransportMessage *rtaComponent_GetMessage(PARCEventQueue *queue);
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ComponentQueue.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ComponentQueue.h
new file mode 100644
index 00000000..33294cbf
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ComponentQueue.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 rta_ComponentQueue.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef Libccnx_rta_ComponentQueue_h
+#define Libccnx_rta_ComponentQueue_h
+
+typedef enum {
+ RTA_UP = 0,
+ RTA_DOWN = 1
+} RtaDirection;
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ComponentStats.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ComponentStats.c
new file mode 100644
index 00000000..3ae60a9c
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ComponentStats.c
@@ -0,0 +1,124 @@
+/*
+ * 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 <string.h>
+
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+#include <ccnx/transport/transport_rta/core/rta_ComponentStats.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+
+struct rta_component_stats {
+ RtaProtocolStack *stack;
+ RtaComponents type;
+ uint64_t stats[STATS_LAST];
+};
+
+char *
+rtaComponentStatType_ToString(RtaComponentStatType statsType)
+{
+ switch (statsType) {
+ case STATS_OPENS:
+ return "opens";
+
+ case STATS_CLOSES:
+ return "closes";
+
+ case STATS_UPCALL_IN:
+ return "upcall_in";
+
+ case STATS_UPCALL_OUT:
+ return "upcall_out";
+
+ case STATS_DOWNCALL_IN:
+ return "downcall_in";
+
+ case STATS_DOWNCALL_OUT:
+ return "downcall_out";
+
+ default:
+ trapIllegalValue(statsType, "Unknown RtaComponentStatType %d", statsType);
+ }
+}
+
+/**
+ * Its ok to call with null stack. that just means when we increment, we won't
+ * also increment stack-wide stats
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaComponentStats *
+rtaComponentStats_Create(RtaProtocolStack *stack, RtaComponents componentType)
+{
+ RtaComponentStats *stats = parcMemory_AllocateAndClear(sizeof(RtaComponentStats));
+ assertNotNull(stats, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(RtaComponentStats));
+ assertTrue(componentType < LAST_COMPONENT, "invalid type %d\n", componentType);
+
+ stats->stack = stack;
+ stats->type = componentType;
+ return stats;
+}
+
+/* Increment and return incremented value */
+uint64_t
+rtaComponentStats_Increment(RtaComponentStats *stats, RtaComponentStatType statsType)
+{
+ assertNotNull(stats, "%s dereferenced a null stats pointer\n", __func__);
+ assertFalse(statsType >= STATS_LAST, "%s incorrect stat type %d\n", __func__, statsType);
+ stats->stats[statsType]++;
+
+ if (stats->stack != NULL) {
+ RtaComponentStats *stack_stats = rtaProtocolStack_GetStats(stats->stack, stats->type);
+ // if stack is not null, then we must get stats from it
+ assertNotNull(stack_stats, "%s got null stack stats\n", __func__);
+ stack_stats->stats[statsType]++;
+ }
+
+ return stats->stats[statsType];
+}
+
+/* Return value */
+uint64_t
+rtaComponentStats_Get(RtaComponentStats *stats, RtaComponentStatType statsType)
+{
+ assertNotNull(stats, "dereferenced a null stats pointer\n");
+ assertFalse(statsType >= STATS_LAST, "incorrect stat statsType %d\n", statsType);
+ return stats->stats[statsType];
+}
+
+/* dump the stats to the given output */
+void
+rtaComponentStats_Dump(RtaComponentStats *stats, FILE *output)
+{
+}
+
+void
+rtaComponentStats_Destroy(RtaComponentStats **statsPtr)
+{
+ RtaComponentStats *stats;
+ assertNotNull(statsPtr, "%s got null stats pointer\n", __func__);
+
+ stats = *statsPtr;
+ assertNotNull(stats, "%s dereferenced a null stats pointer\n", __func__);
+
+ memset(stats, 0, sizeof(RtaComponentStats));
+ parcMemory_Deallocate((void **) &stats);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ComponentStats.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ComponentStats.h
new file mode 100644
index 00000000..6db22a70
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ComponentStats.h
@@ -0,0 +1,172 @@
+/*
+ * 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_ComponentStats.h
+ * @brief <#Brief Description#>
+ *
+ * Statistics are PER CONNECTION PER COMPONENT. Therefore, a component would call
+ * rtaConnection_GetStats(conn, component) to access its stats. Each component must
+ * create its stats counter in _Open and free it in _Close.
+ *
+ * Each ProtocolStack has a PER STACK PER COMPONENT set of statistics too. When a
+ * component creates its stats in _Open, it passes a pointer to its stack, so when
+ * _Increment is called, it will increment both the component's stats and the stack's
+ * stats.
+ *
+ * For example:
+ *
+ * protocolStack_Init() creates stack-wide stats for each component type.
+ * componentX_Open(stack) creates per-connection stats for that component with
+ * a reference to stack using stats_Create(stack, component_type)
+ * componentX_Y(conn) performs some per-connection activity. It would call
+ * stats_Increment(rtaConnection_GetStats(conn), component_type, stat_type).
+ * That would increment the per-connection per-component stat and if the stack
+ * was not null, would increment the identical component_type, stat_type
+ * stat in the per-stack per-component counters.
+ *
+ *
+ *
+ */
+#ifndef Libccnx_rta_ComponentStats
+#define Libccnx_rta_ComponentStats
+
+#include <ccnx/transport/transport_rta/core/components.h>
+
+struct protocol_stack;
+
+struct rta_component_stats;
+/**
+ *
+ * @see stats_Create
+ */
+typedef struct rta_component_stats RtaComponentStats;
+
+typedef enum {
+ STATS_OPENS,
+ STATS_CLOSES,
+ STATS_UPCALL_IN,
+ STATS_UPCALL_OUT,
+ STATS_DOWNCALL_IN,
+ STATS_DOWNCALL_OUT,
+ STATS_LAST // must be last
+} RtaComponentStatType;
+
+/**
+ * Create a stats component
+ *
+ * If the optional stack is specified, its statistics will be incremented whenever this
+ * stats object is incremented. Otherwise, it may be NULL.
+ *
+ * @param [in] stack Optional protocol stack
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+RtaComponentStats *rtaComponentStats_Create(struct protocol_stack *stack, RtaComponents componentType);
+
+/**
+ * <#OneLineDescription#>
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+char *rtaComponentStatType_ToString(RtaComponentStatType statType);
+
+/**
+ * Increment and return incremented value
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+uint64_t rtaComponentStats_Increment(RtaComponentStats *stats, RtaComponentStatType statType);
+
+/**
+ * Return value
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+uint64_t rtaComponentStats_Get(RtaComponentStats *stats, RtaComponentStatType statType);
+
+/**
+ * dump the stats to the given output
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void rtaComponentStats_Dump(RtaComponentStats *stats, FILE *output);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void rtaComponentStats_Destroy(RtaComponentStats **statsPtr);
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Connection.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Connection.c
new file mode 100644
index 00000000..455fed8d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Connection.c
@@ -0,0 +1,383 @@
+/*
+ * 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 <parc/algol/parc_Memory.h>
+#include <ccnx/transport/common/transport_Message.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Framework_Commands.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+
+#include <ccnx/api/notify/notify_Status.h>
+#include <ccnx/api/control/cpi_ControlFacade.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#ifdef DEBUG_OUTPUT
+#undef DEBUG_OUTPUT
+#endif
+
+#define DEBUG_OUTPUT 0
+
+// SPEW will dump stack traces on reference count events
+#define SPEW 0
+
+struct rta_connection {
+ RtaProtocolStack *stack;
+ RtaFramework *framework;
+
+ // unique id for this connection
+ unsigned connid;
+
+ // opaque component-specific data and their closers
+ void *component_data[LAST_COMPONENT];
+ RtaComponentStats *component_stats[LAST_COMPONENT];
+
+ RtaConnectionStateType connState;
+
+ unsigned messages_in_queue;
+ unsigned refcount;
+
+ PARCJSON *params;
+
+ // api_fd is used in status messages up to the user
+ // transport_fd is used by the API connector to talk w/ API.
+ int api_fd;
+ int transport_fd;
+
+ // is the connection blocked in the given direction?
+ bool blocked_down;
+ bool blocked_up;
+};
+
+RtaComponentStats *
+rtaConnection_GetStats(RtaConnection *conn, RtaComponents component)
+{
+ assertNotNull(conn, "called with null connection\n");
+ return conn->component_stats[component];
+}
+
+RtaConnection *
+rtaConnection_Create(RtaProtocolStack *stack, const RtaCommandOpenConnection *cmdOpen)
+{
+ int i;
+ RtaConnection *conn = parcMemory_AllocateAndClear(sizeof(RtaConnection));
+ assertNotNull(conn, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(RtaConnection));
+
+ conn->stack = stack;
+ conn->framework = rtaProtocolStack_GetFramework(stack);
+ conn->connid = rtaProtocolStack_GetNextConnectionId(stack);
+ conn->connState = CONN_OPEN;
+ conn->api_fd = rtaCommandOpenConnection_GetApiNotifierFd(cmdOpen);
+ conn->transport_fd = rtaCommandOpenConnection_GetTransportNotifierFd(cmdOpen);
+
+ conn->params = parcJSON_Copy(rtaCommandOpenConnection_GetConfig(cmdOpen));
+ conn->refcount = 1;
+
+ conn->blocked_down = false;
+ conn->blocked_up = false;
+
+ for (i = 0; i < LAST_COMPONENT; i++) {
+ conn->component_stats[i] = rtaComponentStats_Create(stack, i);
+ }
+
+ if (DEBUG_OUTPUT) {
+ fprintf(stderr, "%9" PRIu64 " %s connection %p refcount %d\n",
+ rtaFramework_GetTicks(conn->framework), __func__, (void *) conn, conn->refcount);
+ if (SPEW) {
+ longBowRuntime_StackTrace(STDERR_FILENO);
+ }
+
+ char *p = parcJSON_ToString(conn->params);
+ printf("Connection configuration: %s\n", p);
+ parcMemory_Deallocate((void **) &p);
+ }
+
+ return conn;
+}
+
+RtaConnection *
+rtaConnection_Copy(RtaConnection *original)
+{
+ assertNotNull(original, "Called with null parameter");
+ original->refcount++;
+ if (DEBUG_OUTPUT) {
+ fprintf(stderr, "%9" PRIu64 " %s connection %p refcount %d\n",
+ rtaFramework_GetTicks(original->framework), __func__, (void *) original, original->refcount);
+ if (SPEW) {
+ longBowRuntime_StackTrace(STDERR_FILENO);
+ }
+ }
+
+ return original;
+}
+
+void
+rtaConnection_FreeFunc(void **voidPtr)
+{
+ rtaConnection_Destroy((RtaConnection **) voidPtr);
+}
+
+void
+rtaConnection_Destroy(RtaConnection **connPtr)
+{
+ int i;
+ RtaConnection *conn;
+ assertNotNull(connPtr, "called with null connection pointer\n");
+ conn = *connPtr;
+ assertNotNull(conn, "called with null connection\n");
+ assertTrue(conn->refcount > 0, "Called with 0 refcount, invalid state");
+
+ conn->refcount--;
+ if (conn->refcount > 0) {
+ if (DEBUG_OUTPUT) {
+ fprintf(stderr, "%9" PRIu64 " %s connection %p skipped, refcount %u\n",
+ rtaFramework_GetTicks(conn->framework), __func__, (void *) conn, conn->refcount);
+ if (SPEW) {
+ longBowRuntime_StackTrace(STDERR_FILENO);
+ }
+ }
+ return;
+ }
+
+ assertTrue(conn->messages_in_queue == 0, "called when messages are still queued\n");
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s connection %p\n", rtaFramework_GetTicks(conn->framework), __func__, (void *) conn);
+ if (SPEW) {
+ longBowRuntime_StackTrace(STDERR_FILENO);
+ }
+ }
+
+ // Ok, at this point there's nothing left in queue, so we can
+ // get rid of the container now
+
+ for (i = 0; i < LAST_COMPONENT; i++) {
+ rtaComponentStats_Destroy(&conn->component_stats[i]);
+ }
+
+ rtaFramework_RemoveConnection(conn->framework, conn);
+ parcJSON_Release(&conn->params);
+ parcMemory_Deallocate((void **) &conn);
+ *connPtr = NULL;
+}
+
+RtaProtocolStack *
+rtaConnection_GetStack(RtaConnection *conn)
+{
+ assertNotNull(conn, "called with null connection\n");
+ return conn->stack;
+}
+
+/*
+ * Used to store per-connection state from Open.
+ * Should be freed in Close, but you don't need to set it NULL.
+ */
+void
+rtaConnection_SetPrivateData(RtaConnection *conn,
+ RtaComponents component,
+ void *private)
+{
+ assertNotNull(conn, "called with null connection\n");
+ conn->component_data[component] = private;
+}
+
+/*
+ * Used to store per-connection state from Open
+ */
+void *
+rtaConnection_GetPrivateData(RtaConnection *conn,
+ RtaComponents component)
+{
+ assertNotNull(conn, "called with null connection\n");
+ return conn->component_data[component];
+}
+
+RtaConnectionStateType
+rtaConnection_GetState(RtaConnection *conn)
+{
+ assertNotNull(conn, "called with null connection\n");
+ return conn->connState;
+}
+
+void
+rtaConnection_SetState(RtaConnection *conn, RtaConnectionStateType connState)
+{
+ assertNotNull(conn, "called with null connection\n");
+ conn->connState = connState;
+ rtaProtocolStack_ConnectionStateChange(conn->stack, conn);
+}
+
+/*
+ * returns number in queue, including this one
+ */
+unsigned
+rtaConnection_IncrementMessagesInQueue(RtaConnection *conn)
+{
+ assertNotNull(conn, "called with null connection\n");
+ assertTrue(conn->connState != CONN_CLOSED, "%s called when connection closed\n", __func__);
+ conn->messages_in_queue++;
+ return conn->messages_in_queue;
+}
+
+unsigned
+rtaConnection_DecrementMessagesInQueue(RtaConnection *conn)
+{
+ assertNotNull(conn, "called with null connection\n");
+ assertTrue(conn->messages_in_queue > 0, "Trying to decrement a queue with 0 messages already");
+
+ conn->messages_in_queue--;
+ return conn->messages_in_queue;
+}
+
+int
+rtaConnection_GetApiFd(RtaConnection *conn)
+{
+ assertNotNull(conn, "called with null connection\n");
+ return conn->api_fd;
+}
+
+
+int
+rtaConnection_GetTransportFd(RtaConnection *conn)
+{
+ assertNotNull(conn, "called with null connection\n");
+ return conn->transport_fd;
+}
+
+int
+rtaConnection_GetStackId(RtaConnection *conn)
+{
+ return rtaProtocolStack_GetStackId(conn->stack);
+}
+
+unsigned
+rtaConnection_MessagesInQueue(RtaConnection *conn)
+{
+ assertNotNull(conn, "called with null connection\n");
+ return conn->messages_in_queue;
+}
+
+unsigned
+rtaConnection_GetConnectionId(const RtaConnection *conn)
+{
+ assertNotNull(conn, "called with null connection\n");
+ return conn->connid;
+}
+
+void
+rtaConnection_SendNotifyStatus(RtaConnection *conn, RtaComponents component, RtaDirection direction, const NotifyStatus *status)
+{
+ PARCJSON *json = notifyStatus_ToJSON(status);
+
+ CCNxTlvDictionary *notification = ccnxControlFacade_CreateNotification(json);
+ parcJSON_Release(&json);
+
+ TransportMessage *tm = transportMessage_CreateFromDictionary(notification);
+ ccnxTlvDictionary_Release(&notification);
+
+ PARCEventQueue *out = rtaComponent_GetOutputQueue(conn, component, direction);
+
+ transportMessage_SetInfo(tm, rtaConnection_Copy(conn), rtaConnection_FreeFunc);
+ rtaComponent_PutMessage(out, tm);
+}
+
+void
+rtaConnection_SendStatus(RtaConnection *conn,
+ RtaComponents component,
+ RtaDirection direction,
+ NotifyStatusCode code,
+ CCNxName *optionalName,
+ const char *optionalMessage)
+{
+ NotifyStatus *status = notifyStatus_Create(conn->api_fd, code, optionalName, optionalMessage);
+ rtaConnection_SendNotifyStatus(conn, component, direction, status);
+ notifyStatus_Release(&status);
+}
+
+RtaConnection *
+rtaConnection_GetFromTransport(TransportMessage *tm)
+{
+ return (RtaConnection *) transportMessage_GetInfo(tm);
+}
+
+RtaFramework *
+rtaConnection_GetFramework(const RtaConnection *connection)
+{
+ assertNotNull(connection, "called with null connection");
+ return connection->framework;
+}
+
+PARCJSON *
+rtaConnection_GetParameters(RtaConnection *conn)
+{
+ assertNotNull(conn, "called with null connection");
+ return conn->params;
+}
+
+bool
+rtaConnection_BlockedDown(const RtaConnection *connection)
+{
+ assertNotNull(connection, "Parameter connection must be non-null");
+ return (connection->connState != CONN_OPEN) || connection->blocked_down;
+}
+
+bool
+rtaConnection_BlockedUp(const RtaConnection *connection)
+{
+ assertNotNull(connection, "Parameter connection must be non-null");
+ return (connection->connState != CONN_OPEN) || connection->blocked_up;
+}
+
+void
+rtaConnection_SetBlockedDown(RtaConnection *connection)
+{
+ assertNotNull(connection, "Parameter connection must be non-null");
+ connection->blocked_down = true;
+ rtaProtocolStack_ConnectionStateChange(connection->stack, connection);
+}
+
+void
+rtaConnection_ClearBlockedDown(RtaConnection *connection)
+{
+ assertNotNull(connection, "Parameter connection must be non-null");
+ connection->blocked_down = false;
+ rtaProtocolStack_ConnectionStateChange(connection->stack, connection);
+}
+
+void
+rtaConnection_SetBlockedUp(RtaConnection *connection)
+{
+ assertNotNull(connection, "Parameter connection must be non-null");
+ connection->blocked_up = true;
+ rtaProtocolStack_ConnectionStateChange(connection->stack, connection);
+}
+
+void
+rtaConnection_ClearBlockedUp(RtaConnection *connection)
+{
+ assertNotNull(connection, "Parameter connection must be non-null");
+ connection->blocked_up = false;
+ rtaProtocolStack_ConnectionStateChange(connection->stack, connection);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Connection.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Connection.h
new file mode 100644
index 00000000..8619ef96
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Connection.h
@@ -0,0 +1,457 @@
+/*
+ * 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_Connection.h
+ * @brief <#Brief Description#>
+ *
+ * A connection embodies an API connection to the forwarder. Multiple
+ * connections are multiplexed over one stack. A connection, however,
+ * is largely independent of a particular stack. All the RTA connections
+ * are stored in RtaConnectionTable, which is managed by the Framework.
+ *
+ * A problem arises using queues between components, because there may
+ * be messages in queue that cannot be free'd without slogging through
+ * all the queues.
+ *
+ * Therefore, a connection tracks the number of messages in queue and
+ * will not be freed until all messages in queue are flushed.
+ *
+ * A connection carries an "isopen" flag. If it is false, no new
+ * messages can go in to the connection. Any message dequeued that
+ * references a closed connection discarded.
+ *
+ * Once the connection reaches 0 messages in queue, if it is closed,
+ * it is elegible for garbage collection. componentServq will call
+ * the _Destroy() method. Destroy() only works if the refcount for
+ * the connection is 0. If the ProtocolStack still has a reference
+ * to the connection, the connection will not be destroyed until
+ * the protocol stack calls Destroy.
+ *
+ * A Connection may live longer than its protocol stack. In the _Destroy,
+ * it should not make reference to the protocol stack.
+ *
+ */
+#ifndef Libccnx_Rta_Connection_h
+#define Libccnx_Rta_Connection_h
+
+#include <sys/queue.h>
+#include <ccnx/transport/common/transport.h>
+#include <ccnx/transport/transport_rta/core/components.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/core/rta_ComponentStats.h>
+#include <ccnx/transport/transport_rta/commands/rta_CommandOpenConnection.h>
+
+#include <ccnx/api/notify/notify_Status.h>
+
+struct rta_connection;
+/**
+ *
+ * @see rtaConnection_Create
+ */
+typedef struct rta_connection RtaConnection;
+
+typedef enum {
+ CONN_OPEN,
+ CONN_CLOSED,
+ CONN_PAUSED
+} RtaConnectionStateType;
+
+/**
+ * Create a connection and set the refcount to 1. If the connection
+ * pointer is stored by multiple entities, they should call
+ * IncrementRefcount. Calling _Destroy() decrements the refcount.
+ *
+ * transport_fd is our side of the data socketpair provided by rtaTransport.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaConnection *rtaConnection_Create(RtaProtocolStack *stack, const RtaCommandOpenConnection *cmdOpen);
+
+/**
+ * Get a reference counted copy
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaConnection *rtaConnection_Copy(RtaConnection *original);
+
+/**
+ * Destroys the object if this call decrements the refcount to 0.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaConnection_Destroy(RtaConnection **connPtr);
+
+/**
+ * Same as _Destroy, but for using in a TransportMessage Info.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaConnection_FreeFunc(void **voidPtr);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+RtaProtocolStack *rtaConnection_GetStack(RtaConnection *connection);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+RtaFramework *rtaConnection_GetFramework(const RtaConnection *connection);
+
+/**
+ *
+ * Used to store per-connection state from Open.
+ * Should be freed in Close, but you don't need to set it NULL.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void rtaConnection_SetPrivateData(RtaConnection *connection, RtaComponents component, void *private);
+
+/**
+ * Used to store per-connection state from Open
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void *rtaConnection_GetPrivateData(RtaConnection *connection, RtaComponents component);
+
+/**
+ * Returns the connection state (open, paused, closed)
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaConnectionStateType rtaConnection_GetState(RtaConnection *connection);
+
+/**
+ * Sets the connection state
+ *
+ * The API connector manages the connection state. open means all messages
+ * may flow. Paused means no new messages flow. closed means all existing
+ * messages will be destroyed.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaConnection_SetState(RtaConnection *connection, RtaConnectionStateType state);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+RtaComponentStats *rtaConnection_GetStats(RtaConnection *connection, RtaComponents component);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+unsigned rtaConnection_IncrementMessagesInQueue(RtaConnection *connection);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+unsigned rtaConnection_DecrementMessagesInQueue(RtaConnection *connection);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+unsigned rtaConnection_MessagesInQueue(RtaConnection *connection);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+unsigned rtaConnection_GetConnectionId(const RtaConnection *connection);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+int rtaConnection_GetStackId(RtaConnection *connection);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+int rtaConnection_GetApiFd(RtaConnection *connection);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+int rtaConnection_GetTransportFd(RtaConnection *connection);
+
+/**
+ * Creates a status message (see ccnx/api/notify) and sends it up or down the stack.
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+extern void rtaConnection_SendStatus(RtaConnection *connection,
+ RtaComponents component,
+ RtaDirection direction,
+ NotifyStatusCode code,
+ CCNxName *optionalName,
+ const char *optionalMessage);
+
+/**
+ * Creates a status message (see ccnx/api/notify) and sends it up or down the stack.
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaConnection *rtaConnection_GetFromTransport(TransportMessage *tm);
+
+/**
+ * Creates a status message (see ccnx/api/notify) and sends it up or down the stack.
+ *
+ * <#Discussion#>
+ *
+ * @param connection
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *rtaConnection_GetParameters(RtaConnection *connection);
+
+/**
+ * Is the connection blocked in the down direction?
+ *
+ * Will return true if the connection is not open (DOWN or PAUSED state) or if the
+ * given direction is blocked.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return true Connection blocked, will not accept any more packets in down direction
+ * @return false Connection not blocked in down direction
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool rtaConnection_BlockedDown(const RtaConnection *connection);
+
+/**
+ * Is the connection blocked in the up direction?
+ *
+ * Will return true if the connection is not open (DOWN or PAUSED state) or if the
+ * given direction is blocked.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return true Connection blocked, will not accept any more packets in up direction
+ * @return false Connection not blocked in up direction
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool rtaConnection_BlockedUp(const RtaConnection *connection);
+
+void rtaConnection_SetBlockedDown(RtaConnection *connection);
+void rtaConnection_ClearBlockedDown(RtaConnection *connection);
+
+void rtaConnection_SetBlockedUp(RtaConnection *connection);
+void rtaConnection_ClearBlockedUp(RtaConnection *connection);
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ConnectionTable.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ConnectionTable.c
new file mode 100644
index 00000000..2b1e8d7e
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ConnectionTable.c
@@ -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.
+ */
+
+/*
+ * Uses a linked list right now, but should be hash tables on the keys we use.
+ */
+#include <config.h>
+#include <stdio.h>
+#include <sys/queue.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Framework_Services.h>
+#include <ccnx/transport/transport_rta/core/rta_ConnectionTable.h>
+
+#define DEBUG_OUTPUT 0
+
+typedef struct rta_connection_entry {
+ RtaConnection *connection;
+
+ TAILQ_ENTRY(rta_connection_entry) list;
+} RtaConnectionEntry;
+
+struct rta_connection_table {
+ size_t max_elements;
+ size_t count_elements;
+ TableFreeFunc *freefunc;
+ TAILQ_HEAD(, rta_connection_entry) head;
+};
+
+
+/**
+ * Create a connection table of the given size
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaConnectionTable *
+rtaConnectionTable_Create(size_t elements, TableFreeFunc *freefunc)
+{
+ RtaConnectionTable *table = parcMemory_AllocateAndClear(sizeof(RtaConnectionTable));
+ assertNotNull(table, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(RtaConnectionTable));
+ TAILQ_INIT(&table->head);
+ table->max_elements = elements;
+ table->count_elements = 0;
+ table->freefunc = freefunc;
+ return table;
+}
+
+/**
+ * Destroy the connection table, and it will call rtaConnection_Destroy()
+ * on each connection in the table.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+rtaConnectionTable_Destroy(RtaConnectionTable **tablePtr)
+{
+ RtaConnectionTable *table;
+
+ assertNotNull(tablePtr, "Called with null parameter");
+ table = *tablePtr;
+ assertNotNull(table, "Called with parameter that dereferences to null");
+
+ while (!TAILQ_EMPTY(&table->head)) {
+ RtaConnectionEntry *entry = TAILQ_FIRST(&table->head);
+ TAILQ_REMOVE(&table->head, entry, list);
+ if (table->freefunc) {
+ table->freefunc(&entry->connection);
+ }
+ parcMemory_Deallocate((void **) &entry);
+ }
+
+ parcMemory_Deallocate((void **) &table);
+ *tablePtr = NULL;
+}
+
+/**
+ * Add a connetion to the table. Stores the reference provided (does not copy).
+ * Returns 0 on success, -1 on error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int
+rtaConnectionTable_AddConnection(RtaConnectionTable *table, RtaConnection *connection)
+{
+ assertNotNull(table, "Called with null parameter RtaConnectionTable");
+ assertNotNull(connection, "Called with null parameter RtaConnection");
+
+ if (table->count_elements < table->max_elements) {
+ table->count_elements++;
+ RtaConnectionEntry *entry = parcMemory_AllocateAndClear(sizeof(RtaConnectionEntry));
+ assertNotNull(entry, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(RtaConnectionEntry));
+ entry->connection = connection;
+ TAILQ_INSERT_TAIL(&table->head, entry, list);
+ return 0;
+ }
+ return -1;
+}
+
+/**
+ * Lookup a connection.
+ * Returns NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaConnection *
+rtaConnectionTable_GetByApiFd(RtaConnectionTable *table, int api_fd)
+{
+ assertNotNull(table, "Called with null parameter RtaConnectionTable");
+
+ RtaConnectionEntry *entry;
+ TAILQ_FOREACH(entry, &table->head, list)
+ {
+ if (rtaConnection_GetApiFd(entry->connection) == api_fd) {
+ return entry->connection;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Lookup a connection.
+ * Returns NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaConnection *
+rtaConnectionTable_GetByTransportFd(RtaConnectionTable *table, int transport_fd)
+{
+ assertNotNull(table, "Called with null parameter RtaConnectionTable");
+
+ RtaConnectionEntry *entry;
+ TAILQ_FOREACH(entry, &table->head, list)
+ {
+ if (rtaConnection_GetTransportFd(entry->connection) == transport_fd) {
+ return entry->connection;
+ }
+ }
+ return NULL;
+}
+
+
+/**
+ * Remove a connection from the table, calling rtaConnection_Destroy() on it.
+ * Returns 0 on success, -1 if not found (or error)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int
+rtaConnectionTable_Remove(RtaConnectionTable *table, RtaConnection *connection)
+{
+ assertNotNull(table, "Called with null parameter RtaConnectionTable");
+ assertNotNull(connection, "Called with null parameter RtaConnection");
+
+ RtaConnectionEntry *entry;
+ TAILQ_FOREACH(entry, &table->head, list)
+ {
+ if (entry->connection == connection) {
+ assertTrue(table->count_elements > 0, "Invalid state, found an entry, but count_elements is zero");
+ table->count_elements--;
+ TAILQ_REMOVE(&table->head, entry, list);
+ if (table->freefunc) {
+ table->freefunc(&entry->connection);
+ }
+ parcMemory_Deallocate((void **) &entry);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Remove all connections in a given stack_id, calling rtaConnection_Destroy() on it.
+ * Returns 0 on success, -1 if not found (or error)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int
+rtaConnectionTable_RemoveByStack(RtaConnectionTable *table, int stack_id)
+{
+ assertNotNull(table, "Called with null parameter RtaConnectionTable");
+
+ RtaConnectionEntry *entry = TAILQ_FIRST(&table->head);
+ while (entry != NULL) {
+ RtaConnectionEntry *temp = TAILQ_NEXT(entry, list);
+ if (rtaConnection_GetStackId(entry->connection) == stack_id) {
+ assertTrue(table->count_elements > 0, "Invalid state, found an entry, but count_elements is zero");
+ table->count_elements--;
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 "%s stack_id %d conn %p\n",
+ rtaFramework_GetTicks(rtaConnection_GetFramework(entry->connection)),
+ __func__,
+ stack_id,
+ (void *) entry->connection);
+ }
+
+ TAILQ_REMOVE(&table->head, entry, list);
+ if (table->freefunc) {
+ table->freefunc(&entry->connection);
+ }
+
+ if (DEBUG_OUTPUT) {
+ printf("%9s %s FREEFUNC RETURNS\n",
+ " ", __func__);
+ }
+
+ parcMemory_Deallocate((void **) &entry);
+ }
+ entry = temp;
+ }
+ return 0;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ConnectionTable.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ConnectionTable.h
new file mode 100644
index 00000000..5cb1cb3e
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ConnectionTable.h
@@ -0,0 +1,109 @@
+/*
+ * 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_ConnectionTable.h
+ * @brief Data structure of connections. It is managed by rtaFramework.
+ *
+ */
+
+#ifndef Libccnx_rta_ConnectionTable_h
+#define Libccnx_rta_ConnectionTable_h
+
+#include "rta_Connection.h"
+
+struct rta_connection_table;
+typedef struct rta_connection_table RtaConnectionTable;
+
+typedef void (TableFreeFunc)(RtaConnection **connection);
+
+/**
+ * Create a connection table of the given size. Whenever a
+ * connection is removed, the freefunc is called. Be sure that
+ * does not in turn call back in to the connection table.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaConnectionTable *rtaConnectionTable_Create(size_t elements, TableFreeFunc *freefunc);
+
+/**
+ * Destroy the connection table, and it will call freefunc()
+ * on each connection in the table.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaConnectionTable_Destroy(RtaConnectionTable **tablePtr);
+
+/**
+ * Add a connetion to the table. Stores the reference provided (does not copy).
+ * Returns 0 on success, -1 on error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int rtaConnectionTable_AddConnection(RtaConnectionTable *table, RtaConnection *connection);
+
+/**
+ * Lookup a connection.
+ * Returns NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaConnection *rtaConnectionTable_GetByApiFd(RtaConnectionTable *table, int api_fd);
+
+/**
+ * Lookup a connection.
+ * Returns NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaConnection *rtaConnectionTable_GetByTransportFd(RtaConnectionTable *table, int transport_fd);
+
+/**
+ * Remove a connection from the table, calling freefunc() on it.
+ * Returns 0 on success, -1 if not found (or error)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int rtaConnectionTable_Remove(RtaConnectionTable *table, RtaConnection *connection);
+
+/**
+ * Remove all connections in a given stack_id, calling freefunc() on it.
+ * Returns 0 on success, -1 if not found (or error)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int rtaConnectionTable_RemoveByStack(RtaConnectionTable *table, int stack_id);
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework.c
new file mode 100644
index 00000000..ada629e0
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework.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.
+ */
+
+/**
+ * This module implements the _Create(), _Start(), and _Destroy() methods.
+ * It also has various utilities for timers and events.
+ *
+ * The command channel is processed in rta_Framework_Commands.c.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <errno.h>
+
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <parc/algol/parc_EventSignal.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Framework.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+#include <ccnx/transport/transport_rta/core/rta_ConnectionTable.h>
+#include <ccnx/transport/common/transport_Message.h>
+#include <ccnx/transport/common/transport_private.h>
+
+#include <ccnx/transport/transport_rta/connectors/connector_Api.h>
+#include <ccnx/transport/transport_rta/connectors/connector_Forwarder.h>
+#include <ccnx/transport/transport_rta/components/component_Codec.h>
+#include <ccnx/transport/transport_rta/components/component_Flowcontrol.h>
+
+#include <ccnx/transport/transport_rta/commands/rta_CommandTransmitStatistics.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#ifndef DEBUG_OUTPUT
+#define DEBUG_OUTPUT 0
+#endif
+
+#include "rta_Framework_Commands.h"
+
+// ===================================================
+
+// event callbacks
+static void _signal_cb(int signalNumber, PARCEventType event, void *arg);
+static void _tick_cb(int, PARCEventType, void *);
+static void transmitStatisticsCallback(int fd, PARCEventType what, void *user_data);
+
+
+// ===========================================
+// Public API (create, start, destroy)
+// stop are done via the command channel
+// start cannot be done via the command channel, as its not running until after start.
+
+void
+rta_Framework_LockStatus(RtaFramework *framework)
+{
+ int res = pthread_mutex_lock(&framework->status_mutex);
+ assertTrue(res == 0, "error from pthread_mutex_lock: %d", res);
+}
+
+void
+rta_Framework_UnlockStatus(RtaFramework *framework)
+{
+ int res = pthread_mutex_unlock(&framework->status_mutex);
+ assertTrue(res == 0, "error from pthread_mutex_unlock: %d", res);
+}
+
+void
+rta_Framework_WaitStatus(RtaFramework *framework)
+{
+ int res = pthread_cond_wait(&framework->status_cv, &framework->status_mutex);
+ assertTrue(res == 0, "error from pthread_mutex_unlock: %d", res);
+}
+
+void
+rta_Framework_BroadcastStatus(RtaFramework *framework)
+{
+ int res = pthread_cond_broadcast(&framework->status_cv);
+ assertTrue(res == 0, "error from pthread_mutex_unlock: %d", res);
+}
+
+
+/**
+ * This is called whenever the connection table wants to free a connection.
+ * It should call the protocol stack's closers on the connection, then
+ * destroy the connection. It is called either (a) inside the worker thread,
+ * or (b) after the worker thread has stopped, so no locking needed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+rtaFramework_ConnectionTableFreeFunc(RtaConnection **connectionPtr)
+{
+ RtaConnection *connection;
+ assertNotNull(connectionPtr, "Called with null double pointer");
+ connection = *connectionPtr;
+ assertNotNull(connection, "Parameter must not dereference to null");
+
+ if (rtaConnection_GetState(connection) != CONN_CLOSED) {
+ rtaFramework_CloseConnection(rtaConnection_GetFramework(connection), connection);
+ }
+
+ rtaConnection_Destroy(connectionPtr);
+}
+
+static void
+_signal_cb(int signalNumber, PARCEventType event, void *arg)
+{
+}
+
+static void
+rtaFramework_InitializeEventScheduler(RtaFramework *framework)
+{
+ framework->base = parcEventScheduler_Create();
+ assertNotNull(framework->base, "Could not initialize event scheduler!");
+
+ framework->signal_pipe = parcEventSignal_Create(framework->base, SIGPIPE, PARCEventType_Signal | PARCEventType_Persist, _signal_cb, framework);
+ parcEventSignal_Start(framework->signal_pipe);
+
+ if (gettimeofday(&framework->starttime, NULL) != 0) {
+ perror("Error getting time of day");
+ trapUnexpectedState("Could not read gettimeofday");
+ }
+}
+
+static void
+rtaFramework_SetupMillisecondTimer(RtaFramework *framework)
+{
+ struct timeval wtnow_timeout;
+
+ // setup a milli-second timer
+ wtnow_timeout.tv_sec = 0;
+ wtnow_timeout.tv_usec = 1000000 / WTHZ;
+
+ framework->tick_event = parcEventTimer_Create(
+ framework->base,
+ PARCEventType_Persist,
+ _tick_cb,
+ (void *) framework);
+
+ parcEventTimer_Start(framework->tick_event, &wtnow_timeout);
+}
+
+static void
+rtaFramework_CreateCommandChannel(RtaFramework *framework)
+{
+ int fd = parcNotifier_Socket(framework->commandNotifier);
+
+ // setup a PARCEventQueue for command_fd
+
+ // Set non-blocking flag
+ int flags = fcntl(fd, F_GETFL, NULL);
+ assertFalse(flags == -1, "fcntl failed to obtain file descriptor flags (%d)", errno);
+ int res = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+ assertTrue(res == 0, "rtaFramework_Create failed to set socket non-blocking: %s", strerror(errno));
+
+ framework->commandEvent = parcEvent_Create(framework->base, fd, PARCEventType_Read | PARCEventType_Persist, rtaFramework_CommandCallback, (void *) framework);
+
+ // The command port is the highest priority
+ parcEvent_SetPriority(framework->commandEvent, PARCEventPriority_Maximum);
+
+ parcEvent_Start(framework->commandEvent);
+
+ // the notifier socket is now ready to fire
+}
+
+/*
+ * Until things get plumbed from above via control messages, we will use
+ * environment variables in the form "RtaFacility_facility=level" with a special facility "RtaFacility_All".
+ * The "All" is processed first, then more specific facilities, so one could set all to a default
+ * level then set specific ones to over-ride.
+ *
+ * Default log level is Error
+ *
+ * Strings:
+ * RtaFacility_Framework
+ * RtaFacility_Api
+ * RtaFacility_Flowcontrol
+ * RtaFacility_Codec
+ * RtaFacility_Forwarder
+ */
+static void
+_setLogLevels(RtaFramework *framework)
+{
+ for (int i = 0; i < RtaLoggerFacility_END; i++) {
+ rtaLogger_SetLogLevel(framework->logger, i, PARCLogLevel_Error);
+ }
+
+ char *levelString = getenv("RtaFacility_All");
+ if (levelString) {
+ PARCLogLevel level = parcLogLevel_FromString(levelString);
+ if (level != PARCLogLevel_All) {
+ for (int i = 0; i < RtaLoggerFacility_END; i++) {
+ rtaLogger_SetLogLevel(framework->logger, i, level);
+ }
+ }
+ }
+
+ // no do specific facilities
+ char buffer[1024];
+ for (int i = 0; i < RtaLoggerFacility_END; i++) {
+ snprintf(buffer, 1024, "RtaFacility_%s", rtaLogger_FacilityString(i));
+ levelString = getenv(buffer);
+ if (levelString) {
+ PARCLogLevel level = parcLogLevel_FromString(levelString);
+ if (level != PARCLogLevel_All) {
+ rtaLogger_SetLogLevel(framework->logger, i, level);
+ }
+ }
+ }
+}
+
+/**
+ * Create a framework. This is a thread-safe function.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaFramework *
+rtaFramework_Create(PARCRingBuffer1x1 *commandRingBuffer, PARCNotifier *commandNotifier)
+{
+ RtaFramework *framework = parcMemory_AllocateAndClear(sizeof(RtaFramework));
+ assertNotNull(framework, "RtaFramework parcMemory_AllocateAndClear returned null");
+
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ framework->logger = rtaLogger_Create(reporter, parcClock_Monotonic());
+ parcLogReporter_Release(&reporter);
+
+ _setLogLevels(framework);
+
+ // setup the event scheduler
+
+ // mutes, condition variable, and protected state for starting
+ // and stopping the event thread from an outside thread.
+ pthread_mutex_init(&framework->status_mutex, NULL);
+ pthread_cond_init(&framework->status_cv, NULL);
+ framework->status = FRAMEWORK_INIT;
+
+ framework->commandRingBuffer = parcRingBuffer1x1_Acquire(commandRingBuffer);
+ framework->commandNotifier = parcNotifier_Acquire(commandNotifier);
+
+ framework->connid_next = 1;
+ TAILQ_INIT(&framework->protocols_head);
+
+ //TODO: make 16384 configurable.
+ framework->connectionTable = rtaConnectionTable_Create(16384, rtaFramework_ConnectionTableFreeFunc);
+ assertNotNull(framework->connectionTable, "Could not allocate conneciton table");
+
+ rtaFramework_InitializeEventScheduler(framework);
+
+ rtaFramework_SetupMillisecondTimer(framework);
+
+ framework->transmit_statistics_event = parcEventTimer_Create(framework->base,
+ PARCEventType_Persist,
+ transmitStatisticsCallback,
+ (void *) framework);
+
+
+ rtaFramework_CreateCommandChannel(framework);
+
+ if (rtaLogger_IsLoggable(framework->logger, RtaLoggerFacility_Framework, PARCLogLevel_Info)) {
+ rtaLogger_Log(framework->logger, RtaLoggerFacility_Framework, PARCLogLevel_Info, __func__,
+ "framework %p created", (void *) framework);
+ }
+
+ return framework;
+}
+
+static void
+rtaFramework_DestroyEventScheduler(RtaFramework *framework)
+{
+ parcEventTimer_Destroy(&(framework->tick_event));
+ parcEventTimer_Destroy(&(framework->transmit_statistics_event));
+
+ if (framework->signal_int != NULL) {
+ parcEventSignal_Destroy(&(framework->signal_int));
+ }
+ if (framework->signal_usr1 != NULL) {
+ parcEventSignal_Destroy(&(framework->signal_usr1));
+ }
+
+ parcEvent_Destroy(&(framework->commandEvent));
+ parcNotifier_Release(&framework->commandNotifier);
+ parcRingBuffer1x1_Release(&framework->commandRingBuffer);
+
+ parcEventSignal_Destroy(&(framework->signal_pipe));
+ parcEventScheduler_Destroy(&(framework->base));
+}
+
+void
+rtaFramework_Destroy(RtaFramework **frameworkPtr)
+{
+ RtaFramework *framework;
+
+ assertNotNull(frameworkPtr, "Parameter must be non-null RtaFramework double pointer");
+ framework = *frameworkPtr;
+ assertNotNull(framework, "Parameter must dereference to non-Null RtaFramework pointer");
+
+ rtaLogger_Log(framework->logger, RtaLoggerFacility_Framework, PARCLogLevel_Info, __func__,
+ "framework %p destroy", (void *) framework);
+
+ // status can be STOPPED or INIT. It's ok to destroy one that's never been started.
+
+ // %%%% LOCK
+ rta_Framework_LockStatus(framework);
+ assertTrue(framework->status == FRAMEWORK_SHUTDOWN ||
+ framework->status == FRAMEWORK_INIT ||
+ framework->status == FRAMEWORK_TEARDOWN,
+ "Framework invalid state, got %d",
+ framework->status);
+ rta_Framework_UnlockStatus(framework);
+ // %%%% UNLOCK
+
+ rtaConnectionTable_Destroy(&framework->connectionTable);
+
+ rtaFramework_DestroyEventScheduler(framework);
+
+ rtaLogger_Release(&framework->logger);
+
+ parcMemory_Deallocate((void **) &framework);
+
+ *frameworkPtr = NULL;
+}
+
+RtaLogger *
+rtaFramework_GetLogger(RtaFramework *framework)
+{
+ return framework->logger;
+}
+
+/**
+ * May block briefly, returns the current status of the framework.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaFrameworkStatus
+rtaFramework_GetStatus(RtaFramework *framework)
+{
+ RtaFrameworkStatus status;
+ // %%%% LOCK
+ rta_Framework_LockStatus(framework);
+ status = framework->status;
+ rta_Framework_UnlockStatus(framework);
+ // %%%% UNLOCK
+ return status;
+}
+
+/**
+ * Blocks until the framework status equals or exeeds the desired status
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaFrameworkStatus
+rtaFramework_WaitForStatus(RtaFramework *framework,
+ RtaFrameworkStatus status)
+{
+ // %%%% LOCK
+ rta_Framework_LockStatus(framework);
+ while (framework->status < status) {
+ rta_Framework_WaitStatus(framework);
+ }
+ rta_Framework_UnlockStatus(framework);
+ // %%%% UNLOCK
+
+ return status;
+}
+
+// =================================================================
+
+// Transport Operations
+
+PARCEventScheduler *
+rtaFramework_GetEventScheduler(RtaFramework *framework)
+{
+ assertNotNull(framework, "Parameter must be non-NULL RtaFramework");
+ return framework->base;
+}
+
+unsigned
+rtaFramework_GetNextConnectionId(RtaFramework *framework)
+{
+ assertNotNull(framework, "Parameter must be non-NULL RtaFramework");
+
+ return framework->connid_next++;
+}
+
+// ============================
+// Internal functions
+
+/*
+ * This is dispatched from the event loop, so its a loosely accurate time
+ */
+static void
+_tick_cb(int fd, PARCEventType what, void *user_data)
+{
+ RtaFramework *framework = (RtaFramework *) user_data;
+ assertTrue(what & PARCEventType_Timeout, "%s got unknown signal %d", __func__, what);
+ framework->clock_ticks++;
+
+ if (framework->killme) {
+ int res;
+
+ if (rtaLogger_IsLoggable(framework->logger, RtaLoggerFacility_Framework, PARCLogLevel_Debug)) {
+ rtaLogger_Log(framework->logger, RtaLoggerFacility_Framework, PARCLogLevel_Debug, __func__,
+ "framework %p exiting base loop", (void *) framework);
+ }
+
+ res = parcEventScheduler_Abort(framework->base);
+ assertTrue(res == 0, "error on parcEventScheduler_Abort: %d", res);
+ }
+}
+
+FILE *GlobalStatisticsFile = NULL;
+
+static void
+transmitStatisticsCallback(int fd, PARCEventType what, void *user_data)
+{
+ RtaFramework *framework = (RtaFramework *) user_data;
+ assertTrue(what & PARCEventType_Timeout, "unknown signal %d", what);
+
+ FrameworkProtocolHolder *holder;
+ TAILQ_FOREACH(holder, &framework->protocols_head, list)
+ {
+ RtaProtocolStack *stack = holder->stack;
+ PARCArrayList *list = rtaProtocolStack_GetStatistics(stack, GlobalStatisticsFile);
+ parcArrayList_Destroy(&list);
+ }
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework.h
new file mode 100644
index 00000000..fbd698d1
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework.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 rta_Framework.h
+ * @brief <#Brief Description#>
+ *
+ * rtaFramework executes inside the worker thread in callback from the event scheduler.
+ *
+ * It provides service functions to components and connectors so they do not need
+ * to be event aware.
+ *
+ * It also manages the command channel to communicate with rtaTransport in the API's thread.
+ *
+ * _Create(), _Start(), and _Destroy() are called from the API's thread. You should not
+ * call _Destroy until rtaFramework_GetStatus() is FRAMEWORK_SHUTDOWN.
+ *
+ * The framework can run in threaded mode or non-threaded mode. Including this one
+ * header gives you both sets of operations, but they are not compatible.
+ *
+ * THREADED MODE:
+ * call _Create
+ * call _Start
+ * ... do work ...
+ * call _Shutdown
+ * call _Destroy
+ *
+ * NON-THREADED MODE
+ * call _Create
+ * ... do work ...
+ * call _Step or _StepCount or _StepTimed
+ * ... do work ...
+ * call _Step or _StepCount or _StepTimed
+ * ... do work ...
+ * call _Teardown
+ * call _Destroy
+ *
+ */
+#ifndef Libccnx_rta_Framework_h
+#define Libccnx_rta_Framework_h
+
+#include <parc/concurrent/parc_RingBuffer_1x1.h>
+#include <parc/concurrent/parc_Notifier.h>
+#include <ccnx/transport/transport_rta/core/rta_Logger.h>
+
+// ===================================
+// External API, used by rtaTransport
+
+struct rta_framework;
+typedef struct rta_framework RtaFramework;
+
+#define RTA_MAX_PRIORITY 0
+#define RTA_NORMAL_PRIORITY 1
+#define RTA_MIN_PRIORITY 2
+
+/**
+ * Transient states: STARTING, STOPPING. You don't want to block waiting for those
+ * as you could easily miss them
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef enum {
+ FRAMEWORK_INIT = 0, /** Initial status after Create() *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ FRAMEWORK_SETUP = 1, /** Configured in non-threaded mode *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+ FRAMEWORK_STARTING = 2, /** Between calling _Start() and the thread running *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ FRAMEWORK_RUNNING = 3, /** After event scheduler thread starts *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ FRAMEWORK_STOPPING = 4, /** When shutdown is finished, but before event scheduler exists *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+ FRAMEWORK_TEARDOWN = 5, /** After cleanup from SETUP *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ FRAMEWORK_SHUTDOWN = 6, /** After event scheduler exits *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+} RtaFrameworkStatus;
+
+/**
+ * Creates the framework context, but does not start the worker thread.
+ * <code>command_fd</code> is the socketpair or pipe (one-way is ok) over which
+ * RTATransport will send commands.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaFramework *rtaFramework_Create(PARCRingBuffer1x1 *commandRingBuffer, PARCNotifier *commandNotifier);
+
+
+void rtaFramework_Destroy(RtaFramework **frameworkPtr);
+
+/**
+ * Returns the Logging system used by the framework
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] framework An allocated RtaFramework
+ *
+ * @retval non-null The Logging system
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaLogger *rtaFramework_GetLogger(RtaFramework *framework);
+
+/**
+ * May block briefly, returns the current status of the framework.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaFrameworkStatus rtaFramework_GetStatus(RtaFramework *framework);
+
+/**
+ * Blocks until the framework status equals or exeeds the desired status
+ * Transient states: STARTING, STOPPING. You don't want to block waiting for those
+ * as you could easily miss them
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaFrameworkStatus rtaFramework_WaitForStatus(RtaFramework *framework,
+ RtaFrameworkStatus status);
+
+
+#include "rta_Framework_Threaded.h"
+#include "rta_Framework_NonThreaded.h"
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Commands.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Commands.c
new file mode 100644
index 00000000..a02efefa
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Commands.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 <config.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <errno.h>
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Framework_private.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/commands/rta_Command.h>
+
+#include <parc/algol/parc_Event.h>
+
+#ifdef DEBUG_OUTPUT
+#undef DEBUG_OUTPUT
+#endif
+
+#define DEBUG_OUTPUT 0
+
+extern FILE *GlobalStatisticsFile;
+
+static bool _rtaFramework_ExecuteCreateStack(RtaFramework *framework, const RtaCommandCreateProtocolStack *createStack);
+static bool _rtaFramework_ExecuteDestroyStack(RtaFramework *framework, const RtaCommandDestroyProtocolStack *destroyStack);
+static bool _rtaFramework_ExecuteOpenConnection(RtaFramework *framework, const RtaCommandOpenConnection *openConnection);
+static bool _rtaFramework_ExecuteCloseConnection(RtaFramework *framework, const RtaCommandCloseConnection *closeConnection);
+static bool _rtaFramework_ExecuteTransmitStatistics(RtaFramework *framework, const RtaCommandTransmitStatistics *transmitStats);
+static bool _rtaFramework_ExecuteShutdownFramework(RtaFramework *framework);
+
+static void rtaFramework_DrainApiDescriptor(int fd);
+
+void
+rtaFramework_CommandCallback(int fd, PARCEventType what, void *user_framework)
+{
+ RtaFramework *framework = (RtaFramework *) user_framework;
+
+ // flag the notifier that we are starting a batch of reads
+ parcNotifier_PauseEvents(framework->commandNotifier);
+
+ RtaCommand *command = NULL;
+ while ((command = rtaCommand_Read(framework->commandRingBuffer)) != NULL) {
+ // The shutdown command can broadcast a change of state before the function
+ // returns, so we need to free the RtaCommand before executing the shutdown.
+ // Therefore, we include the rtaCommand_Destroy() as part of the switch.
+
+ if (rtaCommand_IsOpenConnection(command)) {
+ _rtaFramework_ExecuteOpenConnection(framework, rtaCommand_GetOpenConnection(command));
+ rtaCommand_Release(&command);
+ } else if (rtaCommand_IsCloseConnection(command)) {
+ _rtaFramework_ExecuteCloseConnection(framework, rtaCommand_GetCloseConnection(command));
+ rtaCommand_Release(&command);
+ } else if (rtaCommand_IsCreateProtocolStack(command)) {
+ _rtaFramework_ExecuteCreateStack(framework, rtaCommand_GetCreateProtocolStack(command));
+ rtaCommand_Release(&command);
+ } else if (rtaCommand_IsDestroyProtocolStack(command)) {
+ _rtaFramework_ExecuteDestroyStack(framework, rtaCommand_GetDestroyProtocolStack(command));
+ rtaCommand_Release(&command);
+ } else if (rtaCommand_IsTransmitStatistics(command)) {
+ _rtaFramework_ExecuteTransmitStatistics(framework, rtaCommand_GetTransmitStatistics(command));
+ rtaCommand_Release(&command);
+ } else if (rtaCommand_IsShutdownFramework(command)) {
+ // release the command before executing shutdown
+ rtaCommand_Release(&command);
+ _rtaFramework_ExecuteShutdownFramework(framework);
+ } else {
+ rtaCommand_Display(command, 3);
+ rtaCommand_Release(&command);
+ trapUnexpectedState("Got unknown command type");
+ }
+ }
+
+ // resume notifications
+ parcNotifier_StartEvents(framework->commandNotifier);
+}
+
+// =========================================
+// Internal command processing
+
+/**
+ * Create a protocol holder and insert it in the framework's
+ * protocols_head list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static FrameworkProtocolHolder *
+rtaFramework_CreateProtocolHolder(RtaFramework *framework, PARCJSON *params, uint64_t kv_hash, int stack_id)
+{
+ // request for a new protocol stack, create it
+ FrameworkProtocolHolder *holder = parcMemory_AllocateAndClear(sizeof(FrameworkProtocolHolder));
+ assertNotNull(holder, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(FrameworkProtocolHolder));
+
+ TAILQ_INSERT_TAIL(&framework->protocols_head, holder, list);
+
+ holder->kv_hash = kv_hash;
+ holder->stack_id = stack_id;
+
+ if (DEBUG_OUTPUT) {
+ printf("%s created protocol holder %p hash %" PRIu64 "\n",
+ __func__,
+ (void *) holder,
+ kv_hash);
+ }
+
+ return holder;
+}
+
+/**
+ * Lookup the existing protocol holder for stackid.
+ * Returns NULL if not found.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static FrameworkProtocolHolder *
+rtaFramework_GetProtocolStackByStackId(RtaFramework *framework, int stack_id)
+{
+ FrameworkProtocolHolder *holder;
+ TAILQ_FOREACH(holder, &framework->protocols_head, list)
+ {
+ if (holder->stack_id == stack_id) {
+ return holder;
+ }
+ }
+ return NULL;
+}
+
+static bool
+_rtaFramework_ExecuteCreateStack(RtaFramework *framework, const RtaCommandCreateProtocolStack *createStack)
+{
+ // if we're in INIT mode, we need to bump
+ // wait for notificaiton from event thread
+ if (framework->status == FRAMEWORK_INIT) {
+ rta_Framework_LockStatus(framework);
+ if (framework->status == FRAMEWORK_INIT) {
+ framework->status = FRAMEWORK_SETUP;
+ }
+ rta_Framework_BroadcastStatus(framework);
+ rta_Framework_UnlockStatus(framework);
+ }
+
+ FrameworkProtocolHolder *holder =
+ rtaFramework_GetProtocolStackByStackId(framework, rtaCommandCreateProtocolStack_GetStackId(createStack));
+ assertNull(holder, "Found a holder with stack_id %d, but we're asked to create it!",
+ rtaCommandCreateProtocolStack_GetStackId(createStack));
+
+ uint64_t kv_hash = ccnxStackConfig_HashCode(rtaCommandCreateProtocolStack_GetStackConfig(createStack));
+
+ // this creates it and inserts in framework->protocols_head
+ holder = rtaFramework_CreateProtocolHolder(framework, NULL, kv_hash, rtaCommandCreateProtocolStack_GetStackId(createStack));
+
+ holder->stack =
+ rtaProtocolStack_Create(framework, rtaCommandCreateProtocolStack_GetConfig(createStack), rtaCommandCreateProtocolStack_GetStackId(createStack));
+ rtaProtocolStack_Configure(holder->stack);
+
+ if (DEBUG_OUTPUT) {
+ printf("%s created protocol %p kv_hash %016" PRIX64 " stack_id %d\n",
+ __func__, (void *) holder->stack, kv_hash, rtaCommandCreateProtocolStack_GetStackId(createStack));
+ }
+ return 0;
+}
+
+static bool
+_rtaFramework_ExecuteOpenConnection(RtaFramework *framework, const RtaCommandOpenConnection *openConnection)
+{
+ int res;
+ FrameworkProtocolHolder *holder;
+ RtaConnection *rtaConnection;
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s framework %p\n",
+ rtaFramework_GetTicks(framework), __func__, (void *) framework);
+ }
+
+ holder = rtaFramework_GetProtocolStackByStackId(framework, rtaCommandOpenConnection_GetStackId(openConnection));
+ assertNotNull(holder, "Could not find stack_id %d", rtaCommandOpenConnection_GetStackId(openConnection));
+
+ rtaConnection = rtaConnectionTable_GetByApiFd(framework->connectionTable, rtaCommandOpenConnection_GetApiNotifierFd(openConnection));
+ assertNull(rtaConnection, "Found api_fd %d, but it should not exist!", rtaCommandOpenConnection_GetApiNotifierFd(openConnection));
+
+ rtaConnection = rtaConnection_Create(holder->stack, openConnection);
+ res = rtaConnectionTable_AddConnection(framework->connectionTable, rtaConnection);
+ assertTrue(res == 0, "Got error from rtaConnectionTable_AddConnection: %d", res);
+
+ res = rtaProtocolStack_Open(holder->stack, rtaConnection);
+ assertTrue(res == 0, "Got error from rtaProtocolStack_Open: %d", res);
+
+ rtaConnection_SetState(rtaConnection, CONN_OPEN);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s created connection %p stack_id %d api_fd %d transport_fd %d\n",
+ rtaFramework_GetTicks(framework),
+ __func__,
+ (void *) rtaConnection,
+ rtaCommandOpenConnection_GetStackId(openConnection),
+ rtaCommandOpenConnection_GetApiNotifierFd(openConnection),
+ rtaCommandOpenConnection_GetTransportNotifierFd(openConnection));
+ }
+
+ return true;
+}
+
+
+/**
+ * Mark a connection as closed. If there are no pending
+ * packets in queues, destroy it too.
+ * It's non-static because we call from rta_Framework.c
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int
+rtaFramework_CloseConnection(RtaFramework *framework, RtaConnection *connection)
+{
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s connection %p api_fd %d\n",
+ rtaFramework_GetTicks(framework),
+ __func__, (void *) connection, rtaConnection_GetApiFd(connection));
+ }
+
+ assertFalse(rtaConnection_GetState(connection) == CONN_CLOSED,
+ "connection api_fd %d is already closed", rtaConnection_GetApiFd(connection));
+
+ rtaConnection_SetState(connection, CONN_CLOSED);
+ rtaProtocolStack_Close(rtaConnection_GetStack(connection), connection);
+
+ rtaFramework_DrainApiDescriptor(rtaConnection_GetApiFd(connection));
+
+
+ // Remove it from the connection table, which will free our reference to it.
+
+ rtaConnectionTable_Remove(framework->connectionTable, connection);
+
+ // Done. The rtaConnection will be removed when the last queued
+ // messages for it are gone. We keep the connection holder, so if we do
+ // a Destroy we'll know about it. RtaConnection will call
+ // rtaFramework_RemoveConnection(...) when RtaConnection_Destroy() refcount
+ // is zero and it's going to fully remove the connection.
+
+ return 0;
+}
+
+
+static bool
+_rtaFramework_ExecuteCloseConnection(RtaFramework *framework, const RtaCommandCloseConnection *closeConnection)
+{
+ RtaConnection *connection = rtaConnectionTable_GetByApiFd(framework->connectionTable, rtaCommandCloseConnection_GetApiNotifierFd(closeConnection));
+ assertNotNull(connection, "Could not find api_fd %d", rtaCommandCloseConnection_GetApiNotifierFd(closeConnection));
+
+ return (rtaFramework_CloseConnection(framework, connection) == 0);
+}
+
+/**
+ * When the transport is closing the descriptor
+ * to the API, it should call this to drain any pending but unretrieved
+ * messages out of the API's side of the socket
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+rtaFramework_DrainApiDescriptor(int fd)
+{
+ unsigned count = 0;
+
+ if (DEBUG_OUTPUT) {
+ printf("%s fd %d\n", __func__, fd);
+ }
+
+ // Set non-blocking flag
+ int flags = fcntl(fd, F_GETFL, NULL);
+ assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno);
+ int failure = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+ assertFalse(failure, "fcntl failed to set file descriptor flags (%d)\n", errno);
+
+ // Now drain the user side of stuff they have not read
+ CCNxMetaMessage *msg;
+ while (read(fd, &msg, sizeof(CCNxMetaMessage *)) == sizeof(CCNxMetaMessage *)) {
+ count++;
+ ccnxMetaMessage_Release(&msg);
+ }
+
+ if (DEBUG_OUTPUT) {
+ printf("%s destroyed %u messages\n", __func__, count);
+ }
+}
+
+/**
+ * This is a deferred callback from the RtaConnection when its last TransportMessage
+ * has been purged from the queues.
+ *
+ * Don't call anything inside here that ends up back in the RtaConnection.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+rtaFramework_RemoveConnection(RtaFramework *framework, RtaConnection *rtaConnection)
+{
+ rtaFramework_DrainApiDescriptor(rtaConnection_GetApiFd(rtaConnection));
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s connection %p closing api_fd %d\n",
+ rtaFramework_GetTicks(framework),
+ __func__, (void *) rtaConnection, rtaConnection_GetApiFd(rtaConnection));
+ }
+
+ close(rtaConnection_GetApiFd(rtaConnection));
+ close(rtaConnection_GetTransportFd(rtaConnection));
+}
+
+void
+rtaFramework_DestroyProtocolHolder(RtaFramework *framework, FrameworkProtocolHolder *holder)
+{
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s proto_holder %p\n",
+ rtaFramework_GetTicks(framework),
+ __func__, (void *) holder);
+ }
+
+ // remove any and all connections associated with this protocol stack.
+ // If the connections still have packets floating around in queues, the connection
+ // will stay around until they all get flushed then will destroy on
+ // the last packet destruction
+ rtaConnectionTable_RemoveByStack(framework->connectionTable, holder->stack_id);
+
+ rtaProtocolStack_Destroy(&holder->stack);
+
+ TAILQ_REMOVE(&framework->protocols_head, holder, list);
+
+ parcMemory_Deallocate((void **) &holder);
+}
+
+
+static bool
+_rtaFramework_ExecuteDestroyStack(RtaFramework *framework, const RtaCommandDestroyProtocolStack *destroyStack)
+{
+ FrameworkProtocolHolder *holder = rtaFramework_GetProtocolStackByStackId(framework, rtaCommandDestroyProtocolStack_GetStackId(destroyStack));
+ assertNotNull(holder, "Could not find stack_id %d", rtaCommandDestroyProtocolStack_GetStackId(destroyStack));
+
+ rtaConnectionTable_RemoveByStack(framework->connectionTable, rtaCommandDestroyProtocolStack_GetStackId(destroyStack));
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s proto_holder %p\n",
+ rtaFramework_GetTicks(framework),
+ __func__, (void *) holder);
+ }
+
+ rtaFramework_DestroyProtocolHolder(framework, holder);
+
+ return true;
+}
+
+/**
+ * This will update the shared framework->status, so needs a lock around
+ * the work it does.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+_rtaFramework_ExecuteShutdownFramework(RtaFramework *framework)
+{
+ FrameworkProtocolHolder *holder;
+
+ // %%% LOCK
+ rta_Framework_LockStatus(framework);
+ if (framework->status != FRAMEWORK_RUNNING) {
+ RtaFrameworkStatus status = framework->status;
+ rta_Framework_UnlockStatus(framework);
+ // %%% UNLOCK
+ assertTrue(0, "Invalid state, expected FRAMEWORK_RUNNING or later, got %d", status);
+ return -1;
+ }
+
+ holder = TAILQ_FIRST(&framework->protocols_head);
+ while (holder != NULL) {
+ FrameworkProtocolHolder *temp = TAILQ_NEXT(holder, list);
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s stack_id %d\n",
+ framework->clock_ticks, __func__, holder->stack_id);
+ }
+
+ rtaFramework_DestroyProtocolHolder(framework, holder);
+ holder = temp;
+ }
+
+ parcEventScheduler_Stop(framework->base, &(struct timeval) { .tv_sec = 0, .tv_usec = 1000 });
+ framework->status = FRAMEWORK_STOPPING;
+ rta_Framework_BroadcastStatus(framework);
+ rta_Framework_UnlockStatus(framework);
+ // %%% UNLOCK
+
+ return 0;
+}
+
+// Goes into rta_Framework_Commands.c
+static bool
+_rtaFramework_ExecuteTransmitStatistics(RtaFramework *framework, const RtaCommandTransmitStatistics *transmitStats)
+{
+ if (GlobalStatisticsFile != NULL) {
+ fclose(GlobalStatisticsFile);
+ }
+
+ GlobalStatisticsFile = fopen(rtaCommandTransmitStatistics_GetFilename(transmitStats), "a");
+ assertNotNull(GlobalStatisticsFile, "Failed to open %s", rtaCommandTransmitStatistics_GetFilename(transmitStats));
+
+ if (GlobalStatisticsFile != NULL) {
+ struct timeval period = rtaCommandTransmitStatistics_GetPeriod(transmitStats);
+ parcEventTimer_Start(framework->transmit_statistics_event, &period);
+ } else {
+ fprintf(stderr, "Will not report statistics: Failed to open %s for output.", rtaCommandTransmitStatistics_GetFilename(transmitStats));
+ }
+
+ return 0;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Commands.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Commands.h
new file mode 100644
index 00000000..52f6c2d4
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Commands.h
@@ -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.
+ */
+
+/**
+ * @file <#filename#>
+ * @brief Process the commands from RTATransport
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef Libccnx_rta_Framework_Commands_h
+#define Libccnx_rta_Framework_Commands_h
+
+#include <ccnx/transport/transport_rta/core/rta_Framework.h>
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_private.h>
+
+#include <parc/algol/parc_Event.h>
+
+/**
+ * RtaConnection will call this when RtaConnection_Destroy() refcount reaches
+ * zero and it's actually going to destroy a connection.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+rtaFramework_RemoveConnection(RtaFramework *framework, RtaConnection *rtaConneciton);
+
+/**
+ * called by event scheduler for activity on the Command channel
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaFramework_CommandCallback(int fd, PARCEventType what, void *user_framework);
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.c
new file mode 100644
index 00000000..158f3ec0
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.c
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ */
+
+/**
+ * *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <errno.h>
+
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include "rta_Framework.h"
+#include "rta_ConnectionTable.h"
+#include "rta_Framework_Commands.h"
+
+#ifndef DEBUG_OUTPUT
+#define DEBUG_OUTPUT 0
+#endif
+
+// This is implemented in rta_Framework_Commands
+void
+rtaFramework_DestroyProtocolHolder(RtaFramework *framework, FrameworkProtocolHolder *holder);
+
+/**
+ * If running in non-threaded mode (you don't call _Start), you must manually
+ * turn the crank. This turns it for a single cycle.
+ * Return 0 on success, -1 on error (likely you're running in threaded mode)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int
+rtaFramework_NonThreadedStep(RtaFramework *framework)
+{
+ if (framework->status == FRAMEWORK_INIT) {
+ framework->status = FRAMEWORK_SETUP;
+ }
+
+ assertTrue(framework->status == FRAMEWORK_SETUP,
+ "Framework invalid state for non-threaded, expected %d got %d",
+ FRAMEWORK_SETUP,
+ framework->status
+ );
+
+ if (framework->status != FRAMEWORK_SETUP) {
+ return -1;
+ }
+
+ if (parcEventScheduler_Start(framework->base, PARCEventSchedulerDispatchType_LoopOnce) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * If running in non-threaded mode (you don't call _Start), you must manually
+ * turn the crank. This turns it for a number of cycles.
+ * Return 0 on success, -1 on error (likely you're running in threaded mode)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int
+rtaFramework_NonThreadedStepCount(RtaFramework *framework, unsigned count)
+{
+ if (framework->status == FRAMEWORK_INIT) {
+ framework->status = FRAMEWORK_SETUP;
+ }
+
+ assertTrue(framework->status == FRAMEWORK_SETUP,
+ "Framework invalid state for non-threaded, expected %d got %d",
+ FRAMEWORK_SETUP,
+ framework->status
+ );
+
+ if (framework->status != FRAMEWORK_SETUP) {
+ return -1;
+ }
+
+ while (count-- > 0) {
+ if (parcEventScheduler_Start(framework->base, PARCEventSchedulerDispatchType_LoopOnce) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * If running in non-threaded mode (you don't call _Start), you must manually
+ * turn the crank. This turns it for a given amount of time.
+ * Return 0 on success, -1 on error (likely you're running in threaded mode)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int
+rtaFramework_NonThreadedStepTimed(RtaFramework *framework, struct timeval *duration)
+{
+ if (framework->status == FRAMEWORK_INIT) {
+ framework->status = FRAMEWORK_SETUP;
+ }
+
+ assertTrue(framework->status == FRAMEWORK_SETUP,
+ "Framework invalid state for non-threaded, expected %d got %d",
+ FRAMEWORK_SETUP,
+ framework->status
+ );
+
+ if (framework->status != FRAMEWORK_SETUP) {
+ return -1;
+ }
+
+ parcEventScheduler_Stop(framework->base, duration);
+
+ if (parcEventScheduler_Start(framework->base, 0) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * After a protocol stack is created, you need to Teardown. If you
+ * are running in threaded mode (did a _Start), you should send an asynchronous
+ * SHUTDOWN command instead. This function only works if in the SETUP state
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int
+rtaFramework_Teardown(RtaFramework *framework)
+{
+ FrameworkProtocolHolder *holder;
+
+ assertNotNull(framework, "called with null framework");
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s framework %p\n",
+ rtaFramework_GetTicks(framework),
+ __func__, (void *) framework);
+ }
+
+ // %%% LOCK
+ rta_Framework_LockStatus(framework);
+ if (framework->status != FRAMEWORK_SETUP) {
+ RtaFrameworkStatus status = framework->status;
+ rta_Framework_UnlockStatus(framework);
+ // %%% UNLOCK
+ assertTrue(0, "Invalid state, expected FRAMEWORK_SETUP, got %d", status);
+ return -1;
+ }
+
+ holder = TAILQ_FIRST(&framework->protocols_head);
+ while (holder != NULL) {
+ FrameworkProtocolHolder *temp = TAILQ_NEXT(holder, list);
+ rtaFramework_DestroyProtocolHolder(framework, holder);
+ holder = temp;
+ }
+
+ framework->status = FRAMEWORK_TEARDOWN;
+ rta_Framework_BroadcastStatus(framework);
+ rta_Framework_UnlockStatus(framework);
+ // %%% UNLOCK
+
+ return 0;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.h
new file mode 100644
index 00000000..ca193c83
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.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 rta_Framework_NonThreaded.h
+ * @brief Implementation of the non-threaded api.
+ *
+ * Unless you call one of the _Step methods frequently, the tick clock will be off.
+ *
+ */
+#ifndef Libccnx_rta_Framework_NonThreaded_h
+#define Libccnx_rta_Framework_NonThreaded_h
+
+#include <sys/time.h>
+
+// ==============================
+// NON-THREADED API
+
+/**
+ * If running in non-threaded mode (you don't call _Start), you must manually
+ * turn the crank. This turns it for a single cycle.
+ * Return 0 on success, -1 on error (likely you're running in threaded mode)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int rtaFramework_NonThreadedStep(RtaFramework *framework);
+
+/**
+ * If running in non-threaded mode (you don't call _Start), you must manually
+ * turn the crank. This turns it for a number of cycles.
+ * Return 0 on success, -1 on error (likely you're running in threaded mode)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int rtaFramework_NonThreadedStepCount(RtaFramework *framework, unsigned count);
+
+/**
+ * If running in non-threaded mode (you don't call _Start), you must manually
+ * turn the crank. This turns it for a given amount of time.
+ * Return 0 on success, -1 on error (likely you're running in threaded mode)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int rtaFramework_NonThreadedStepTimed(RtaFramework *framework, struct timeval *duration);
+
+
+/**
+ * After a protocol stack is created, you need to Teardown. If you
+ * are running in threaded mode (did a _Start), you should send an asynchronous
+ * SHUTDOWN command instead. This function only works if in the SETUP state
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int rtaFramework_Teardown(RtaFramework *framework);
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Services.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Services.c
new file mode 100644
index 00000000..cf2c8cd3
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Services.c
@@ -0,0 +1,44 @@
+/*
+ * 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 <parc/algol/parc_Memory.h>
+#include <sys/queue.h>
+
+#include "rta_Framework.h"
+#include "rta_Framework_private.h"
+#include "rta_Framework_Services.h"
+
+ticks
+rtaFramework_GetTicks(RtaFramework *framework)
+{
+ assertNotNull(framework, "Parameter framework cannot be null");
+ return framework->clock_ticks;
+}
+
+uint64_t
+rtaFramework_TicksToUsec(ticks tick)
+{
+ return FC_USEC_PER_TICK * tick;
+}
+
+ticks
+rtaFramework_UsecToTicks(unsigned usec)
+{
+ return MSEC_TO_TICKS(usec / 1000);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Services.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Services.h
new file mode 100644
index 00000000..f9adf194
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Services.h
@@ -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.
+ */
+
+/**
+ * @file rta_Framework_Services.h
+ * @brief Miscellaneous services offered by the Framework for components and connectors
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef Libccnx_rta_Framework_Services_h
+#define Libccnx_rta_Framework_Services_h
+
+#include "rta_Framework.h"
+
+#include <parc/algol/parc_EventScheduler.h>
+
+// ===================================
+
+typedef uint64_t ticks;
+#define TICK_CMP(a, b) ((int64_t) a - (int64_t) b)
+
+/**
+ * <#One Line Description#>
+ *
+ * If a component wants to use the event scheduler to manage sockets, it
+ * can get a reference to the event base to manage those things
+ *
+ * @param [in] framework <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCEventScheduler *rtaFramework_GetEventScheduler(RtaFramework *framework);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] framework <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+unsigned rtaFramework_GetNextConnectionId(RtaFramework *framework);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] framework <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+ticks rtaFramework_GetTicks(RtaFramework *framework);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] tick <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+extern uint64_t rtaFramework_TicksToUsec(ticks tick);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] usec <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+extern ticks rtaFramework_UsecToTicks(unsigned usec);
+#endif // Libccnx_rta_Framework_Services_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Threaded.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Threaded.c
new file mode 100644
index 00000000..ade2c0a1
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Threaded.c
@@ -0,0 +1,170 @@
+/*
+ * 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 <unistd.h>
+#include <pthread.h>
+
+#include <errno.h>
+
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include "rta_Framework.h"
+#include "rta_ConnectionTable.h"
+#include "rta_Framework_Commands.h"
+
+#ifndef DEBUG_OUTPUT
+#define DEBUG_OUTPUT 0
+#endif
+
+// the thread function
+static void *_rtaFramework_Run(void *ctx);
+
+/**
+ * Starts the worker thread. Blocks until started
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+rtaFramework_Start(RtaFramework *framework)
+{
+ pthread_attr_t attr;
+
+ // ensure we're in the INIT state, then bump to STARTING
+ // %%% LOCK
+ rta_Framework_LockStatus(framework);
+ if (framework->status == FRAMEWORK_INIT) {
+ framework->status = FRAMEWORK_STARTING;
+ rta_Framework_BroadcastStatus(framework);
+ rta_Framework_UnlockStatus(framework);
+ // %%% UNLOCK
+ } else {
+ RtaFrameworkStatus status = framework->status;
+ rta_Framework_UnlockStatus(framework);
+ // %%% UNLOCK
+ assertTrue(0, "Invalid state, not FRAMEWORK_INIT, got %d", status);
+ return;
+ }
+
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ if (pthread_create(&framework->thread, &attr, _rtaFramework_Run, framework) != 0) {
+ perror("pthread_create");
+ exit(EXIT_FAILURE);
+ }
+
+ if (DEBUG_OUTPUT) {
+ printf("%s framework started %p\n", __func__, (void *) framework);
+ }
+
+ // wait for notificaiton from event thread
+ rta_Framework_LockStatus(framework);
+ while (framework->status == FRAMEWORK_INIT) {
+ rta_Framework_WaitStatus(framework);
+ }
+ rta_Framework_UnlockStatus(framework);
+
+ if (DEBUG_OUTPUT) {
+ printf("%s framework running %p\n", __func__, (void *) framework);
+ }
+}
+
+static void *
+_rtaFramework_Run(void *ctx)
+{
+ RtaFramework *framework = (RtaFramework *) ctx;
+
+ // %%% LOCK
+ rta_Framework_LockStatus(framework);
+ if (framework->status != FRAMEWORK_STARTING) {
+ assertTrue(0, "Invalid state, expected before %d, got %d", FRAMEWORK_STARTING, framework->status);
+ rta_Framework_UnlockStatus(framework);
+ // %%% UNLOCK
+ pthread_exit(NULL);
+ }
+ framework->status = FRAMEWORK_RUNNING;
+
+ // Set our thread name, only used to diagnose a crash or in debugging
+#if __APPLE__
+ pthread_setname_np("RTA Framework");
+#else
+ pthread_setname_np(framework->thread, "RTA Framework");
+#endif
+
+ rta_Framework_BroadcastStatus(framework);
+ rta_Framework_UnlockStatus(framework);
+ // %%% UNLOCK
+
+ if (DEBUG_OUTPUT) {
+ const int bufferLength = 1024;
+ char frameworkName[bufferLength];
+ pthread_getname_np(framework->thread, frameworkName, bufferLength);
+ printf("Framework thread running: '%s'\n", frameworkName);
+ }
+
+ // blocks
+ parcEventScheduler_Start(framework->base, PARCEventSchedulerDispatchType_Blocking);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s existed parcEventScheduler_Start\n", framework->clock_ticks, __func__);
+ }
+
+ // %%% LOCK
+ rta_Framework_LockStatus(framework);
+ framework->status = FRAMEWORK_SHUTDOWN;
+ rta_Framework_BroadcastStatus(framework);
+ rta_Framework_UnlockStatus(framework);
+ // %%% UNLOCK
+
+ pthread_exit(NULL);
+}
+
+/**
+ * Stops the worker thread by sending a CommandShutdown.
+ * Blocks until shutdown complete.
+ *
+ * CALLED FROM API's THREAD
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+rtaFramework_Shutdown(RtaFramework *framework)
+{
+ RtaCommand *shutdown = rtaCommand_CreateShutdownFramework();
+ rtaCommand_Write(shutdown, framework->commandRingBuffer);
+ parcNotifier_Notify(framework->commandNotifier);
+ rtaCommand_Release(&shutdown);
+
+ // now block on reading status
+ rtaFramework_WaitForStatus(framework, FRAMEWORK_SHUTDOWN);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Threaded.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Threaded.h
new file mode 100644
index 00000000..ba6e9cb3
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_Threaded.h
@@ -0,0 +1,56 @@
+/*
+ * 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_Framework_Threaded.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef Libccnx_rta_Framework_Threaded_h
+#define Libccnx_rta_Framework_Threaded_h
+
+// =============================
+// THREADED
+
+/**
+ * Starts the worker thread. Blocks until started.
+ *
+ * CALLED FROM API's THREAD
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaFramework_Start(RtaFramework *framework);
+
+/**
+ * Stops the worker thread by sending a CommandShutdown.
+ * Blocks until shutdown complete.
+ *
+ * The caller must provider their side of the command channel
+ *
+ * CALLED FROM API's THREAD
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaFramework_Shutdown(RtaFramework *framework);
+
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_private.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_private.h
new file mode 100644
index 00000000..ffc386c5
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Framework_private.h
@@ -0,0 +1,163 @@
+/*
+ * 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_Framework_private.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef Libccnx_rta_Framework_private_h
+#define Libccnx_rta_Framework_private_h
+
+#include <stdlib.h>
+#include <sys/queue.h>
+#include <pthread.h>
+
+#include "rta_ProtocolStack.h"
+#include "rta_Connection.h"
+#include "rta_Framework_Services.h"
+
+#include "rta_ConnectionTable.h"
+
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_Event.h>
+#include <parc/algol/parc_EventTimer.h>
+#include <parc/algol/parc_EventSignal.h>
+
+// the router's wrapped time frquency is 1 msec
+#define WTHZ 1000
+#define FC_MSEC_PER_TICK (1000 / WTHZ)
+#define FC_USEC_PER_TICK (1000000 / WTHZ)
+#define MSEC_TO_TICKS(msec) ((msec < FC_MSEC_PER_TICK) ? 1 : msec / FC_MSEC_PER_TICK)
+
+// ===================================================
+
+typedef struct framework_protocol_holder {
+ RtaProtocolStack *stack;
+ uint64_t kv_hash;
+ int stack_id;
+
+ TAILQ_ENTRY(framework_protocol_holder) list;
+} FrameworkProtocolHolder;
+
+
+struct rta_framework {
+ PARCRingBuffer1x1 *commandRingBuffer;
+ PARCNotifier *commandNotifier;
+ PARCEvent *commandEvent;
+
+ //struct event_config *cfg;
+ int udp_socket;
+
+ PARCEventScheduler *base;
+
+ PARCEventSignal *signal_int;
+ PARCEventSignal *signal_usr1;
+ PARCEventTimer *tick_event;
+ PARCEvent *udp_event;
+ PARCEventTimer *transmit_statistics_event;
+ PARCEventSignal *signal_pipe;
+
+ struct timeval starttime;
+ ticks clock_ticks; // at WTHZ
+
+ // used by seed48 and nrand48
+ unsigned short seed[3];
+
+ pthread_t thread;
+
+ unsigned connid_next;
+
+ // operations that modify global state need
+ // to be locked.
+ pthread_mutex_t status_mutex;
+ pthread_cond_t status_cv;
+ RtaFrameworkStatus status;
+
+ // signals from outside control thread to event scheduler
+ // that it should exit its event loop. This does
+ // not need to be protected in mutex (its not
+ // a condition variable). We check for this
+ // inside the HZ timer callback.
+ bool killme;
+
+ // A list of all our in-use protocol stacks
+ TAILQ_HEAD(, framework_protocol_holder) protocols_head;
+
+ RtaConnectionTable *connectionTable;
+
+ RtaLogger *logger;
+};
+
+int rtaFramework_CloseConnection(RtaFramework *framework, RtaConnection *connection);
+
+/**
+ * Lock the frameworks state machine status
+ *
+ * Will block until the state machine status is locked
+ *
+ * @param [in] framework An allocated framework
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rta_Framework_LockStatus(RtaFramework *framework);
+
+/**
+ * Unlock the state mahcines status
+ *
+ * Will assert if we do not currently hold the lock
+ *
+ * @param [in] framework An allocated framework
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rta_Framework_UnlockStatus(RtaFramework *framework);
+
+/**
+ * Wait on the state machine's condition variable to be signaled
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] framework An allocated framework
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rta_Framework_WaitStatus(RtaFramework *framework);
+
+/**
+ * Broadcast on the state machine's condition variable (signal it)
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] framework An allocated framework
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rta_Framework_BroadcastStatus(RtaFramework *framework);
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Logger.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Logger.c
new file mode 100644
index 00000000..b8cc8d12
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Logger.c
@@ -0,0 +1,188 @@
+/*
+ * 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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <parc/logging/parc_Log.h>
+#include <ccnx/transport/transport_rta/core/rta_Logger.h>
+
+struct rta_logger {
+ PARCClock *clock;
+
+ PARCLogReporter *reporter;
+ PARCLog *loggerArray[RtaLoggerFacility_END];
+};
+
+static const struct facility_to_string {
+ RtaLoggerFacility facility;
+ const char *string;
+} _facilityToString[] = {
+ { .facility = RtaLoggerFacility_Framework, .string = "Framework" },
+ { .facility = RtaLoggerFacility_ApiConnector, .string = "Api" },
+ { .facility = RtaLoggerFacility_Flowcontrol, .string = "Flowcontrol" },
+ { .facility = RtaLoggerFacility_Codec, .string = "Codec" },
+ { .facility = RtaLoggerFacility_ForwarderConnector, .string = "Forwarder" },
+ { .facility = 0, .string = NULL }
+};
+
+const char *
+rtaLogger_FacilityString(RtaLoggerFacility facility)
+{
+ for (int i = 0; _facilityToString[i].string != NULL; i++) {
+ if (_facilityToString[i].facility == facility) {
+ return _facilityToString[i].string;
+ }
+ }
+ return "Unknown";
+}
+
+static void
+_allocateLoggers(RtaLogger *logger, PARCLogReporter *reporter)
+{
+ trapUnexpectedStateIf(logger->reporter != NULL, "Trying to allocate a reporter when the previous one is not null");
+ logger->reporter = parcLogReporter_Acquire(reporter);
+
+ char hostname[255];
+ int gotHostName = gethostname(hostname, 255);
+ if (gotHostName < 0) {
+ snprintf(hostname, 255, "unknown");
+ }
+
+ for (int i = 0; i < RtaLoggerFacility_END; i++) {
+ logger->loggerArray[i] = parcLog_Create(hostname, rtaLogger_FacilityString(i), "rta", logger->reporter);
+ parcLog_SetLevel(logger->loggerArray[i], PARCLogLevel_Error);
+ }
+}
+
+static void
+_releaseLoggers(RtaLogger *logger)
+{
+ for (int i = 0; i < RtaLoggerFacility_END; i++) {
+ parcLog_Release(&logger->loggerArray[i]);
+ }
+ parcLogReporter_Release(&logger->reporter);
+}
+
+static void
+_destroyer(RtaLogger **loggerPtr)
+{
+ RtaLogger *logger = *loggerPtr;
+ _releaseLoggers(logger);
+ parcClock_Release(&(*loggerPtr)->clock);
+}
+
+parcObject_ExtendPARCObject(RtaLogger, _destroyer, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(rtaLogger, RtaLogger);
+
+parcObject_ImplementRelease(rtaLogger, RtaLogger);
+
+RtaLogger *
+rtaLogger_Create(PARCLogReporter *reporter, const PARCClock *clock)
+{
+ assertNotNull(reporter, "Parameter reporter must be non-null");
+ assertNotNull(clock, "Parameter clock must be non-null");
+
+ RtaLogger *logger = parcObject_CreateAndClearInstance(RtaLogger);
+ if (logger) {
+ logger->clock = parcClock_Acquire(clock);
+ _allocateLoggers(logger, reporter);
+ }
+
+ return logger;
+}
+
+void
+rtaLogger_SetReporter(RtaLogger *logger, PARCLogReporter *reporter)
+{
+ assertNotNull(logger, "Parameter logger must be non-null");
+
+ // save the log level state
+ PARCLogLevel savedLevels[RtaLoggerFacility_END];
+ for (int i = 0; i < RtaLoggerFacility_END; i++) {
+ savedLevels[i] = parcLog_GetLevel(logger->loggerArray[i]);
+ }
+
+ _releaseLoggers(logger);
+
+ _allocateLoggers(logger, reporter);
+
+ // restore log level state
+ for (int i = 0; i < RtaLoggerFacility_END; i++) {
+ parcLog_SetLevel(logger->loggerArray[i], savedLevels[i]);
+ }
+}
+
+void
+rtaLogger_SetClock(RtaLogger *logger, PARCClock *clock)
+{
+ assertNotNull(logger, "Parameter logger must be non-null");
+ parcClock_Release(&logger->clock);
+ logger->clock = parcClock_Acquire(clock);
+}
+
+static void
+_assertInvariants(const RtaLogger *logger, RtaLoggerFacility facility)
+{
+ assertNotNull(logger, "Parameter logger must be non-null");
+ trapOutOfBoundsIf(facility >= RtaLoggerFacility_END, "Invalid facility %d", facility);
+}
+
+void
+rtaLogger_SetLogLevel(RtaLogger *logger, RtaLoggerFacility facility, PARCLogLevel minimumLevel)
+{
+ _assertInvariants(logger, facility);
+ PARCLog *log = logger->loggerArray[facility];
+ parcLog_SetLevel(log, minimumLevel);
+}
+
+bool
+rtaLogger_IsLoggable(const RtaLogger *logger, RtaLoggerFacility facility, PARCLogLevel level)
+{
+ _assertInvariants(logger, facility);
+ PARCLog *log = logger->loggerArray[facility];
+ return parcLog_IsLoggable(log, level);
+}
+
+void
+rtaLogger_Log(RtaLogger *logger, RtaLoggerFacility facility, PARCLogLevel level, const char *module, const char *format, ...)
+{
+ if (rtaLogger_IsLoggable(logger, facility, level)) {
+ // this is logged as the messageid
+ uint64_t logtime = parcClock_GetTime(logger->clock);
+
+ // rtaLogger_IsLoggable asserted invariants so we know facility is in bounds
+ PARCLog *log = logger->loggerArray[facility];
+
+ va_list va;
+ va_start(va, format);
+
+ parcLog_MessageVaList(log, level, logtime, format, va);
+
+ va_end(va);
+ }
+}
+
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Logger.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Logger.h
new file mode 100644
index 00000000..067ad4f1
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_Logger.h
@@ -0,0 +1,227 @@
+/*
+ * 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_Logger.h
+ * @brief Logger for the Rta transport
+ *
+ * A facility based logger to allow selective logging from different parts of Rta
+ *
+ */
+
+#ifndef Rta_rta_Logger_h
+#define Rta_rta_Logger_h
+
+#include <sys/time.h>
+#include <stdarg.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/logging/parc_LogLevel.h>
+#include <parc/logging/parc_LogReporter.h>
+#include <parc/algol/parc_Clock.h>
+
+struct rta_logger;
+typedef struct rta_logger RtaLogger;
+
+/**
+ * Framework - Overall framework
+ * ApiConnector - API Connector
+ * Flowcontrol - Flow controller
+ * Codec - Codec and verification/signing
+ * ForwarderConnector - Forwarder connector
+ */
+typedef enum {
+ RtaLoggerFacility_Framework,
+ RtaLoggerFacility_ApiConnector,
+ RtaLoggerFacility_Flowcontrol,
+ RtaLoggerFacility_Codec,
+ RtaLoggerFacility_ForwarderConnector,
+ RtaLoggerFacility_END // sentinel value
+} RtaLoggerFacility;
+
+/**
+ * Returns a string representation of a facility
+ *
+ * Do not free the returned value.
+ *
+ * @param [in] facility The facility to change to a string
+ *
+ * @retval string A string representation of the facility
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *rtaLogger_FacilityString(RtaLoggerFacility facility);
+
+/**
+ * Returns a string representation of a log level
+ *
+ * Do not free the returned value.
+ *
+ * @param [in] level The level to change to a string
+ *
+ * @retval string A string representation of the level
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *rtaLogger_LevelString(PARCLogLevel level);
+
+/**
+ * Create a logger that uses a given writer and clock
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] writer The output writer
+ * @param [in] clock The clock to use for log messages
+ *
+ * @retval non-null An allocated logger
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaLogger *rtaLogger_Create(PARCLogReporter *reporter, const PARCClock *clock);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaLogger_Release(RtaLogger **loggerPtr);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+RtaLogger *rtaLogger_Acquire(const RtaLogger *logger);
+
+/**
+ * Sets the minimum log level for a facility
+ *
+ * The default log level is ERROR. For a message to be logged, it must be of equal
+ * or higher log level.
+ *
+ * @param [in] logger An allocated logger
+ * @param [in] facility The facility to set the log level for
+ * @param [in] The minimum level to log
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ * RtaLogger *logger = rtaLogger_Create(reporter, parcClock_Wallclock());
+ * parcLogReporter_Release(&reporter);
+ * rtaLogger_SetLogLevel(logger, RtaLoggerFacility_IO, PARCLogLevel_Warning);
+ * }
+ * @endcode
+ */
+void rtaLogger_SetLogLevel(RtaLogger *logger, RtaLoggerFacility facility, PARCLogLevel minimumLevel);
+
+/**
+ * Tests if the log level would be logged
+ *
+ * If the facility would log the given level, returns true. May be used as a
+ * guard around expensive logging functions.
+ *
+ * @param [in] logger An allocated logger
+ * @param [in] facility The facility to test
+ * @param [in] The level to test
+ *
+ * @retval true The given facility would log the given level
+ * @retval false A message of the given level would not be logged
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool rtaLogger_IsLoggable(const RtaLogger *logger, RtaLoggerFacility facility, PARCLogLevel level);
+
+/**
+ * Log a message
+ *
+ * The message will only be logged if it is loggable (rtaLogger_IsLoggable returns true).
+ *
+ * @param [in] logger An allocated RtaLogger
+ * @param [in] facility The facility to log under
+ * @param [in] level The log level of the message
+ * @param [in] module The specific module logging the message
+ * @param [in] format The message with varargs
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaLogger_Log(RtaLogger *logger, RtaLoggerFacility facility, PARCLogLevel level, const char *module, const char *format, ...);
+
+/**
+ * Switch the logger to a new reporter
+ *
+ * Will close the old reporter and re-setup the internal loggers to use the new reporter.
+ * All current log level settings are preserved.
+ *
+ * @param [in] logger An allocated RtaLogger
+ * @param [in] reporter An allocated PARCLogReporter
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaLogger_SetReporter(RtaLogger *logger, PARCLogReporter *reporter);
+
+/**
+ * Set a new clock to use with the logger
+ *
+ * The logger will start getting the time (logged as the messageid) from the specified clock
+ *
+ * @param [in] logger An allocated RtaLogger
+ * @param [in] clock An allocated PARCClock
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaLogger_SetClock(RtaLogger *logger, PARCClock *clock);
+#endif // Rta_rta_Logger_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ProtocolStack.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ProtocolStack.c
new file mode 100644
index 00000000..7bdafbf7
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ProtocolStack.c
@@ -0,0 +1,786 @@
+/*
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <sys/queue.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/time.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_EventQueue.h>
+
+#include <ccnx/transport/transport_rta/core/rta_Framework.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_Services.h>
+
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/core/rta_Connection.h>
+#include <ccnx/transport/transport_rta/core/rta_Component.h>
+#include <ccnx/transport/transport_rta/core/rta_ConnectionTable.h>
+#include <ccnx/transport/transport_rta/core/rta_ComponentStats.h>
+#include <ccnx/transport/common/transport_Message.h>
+#include <ccnx/transport/common/transport_private.h>
+
+#include <ccnx/transport/transport_rta/connectors/connector_Api.h>
+#include <ccnx/transport/transport_rta/connectors/connector_Forwarder.h>
+#include <ccnx/transport/transport_rta/components/component_Codec.h>
+#include <ccnx/transport/transport_rta/components/component_Flowcontrol.h>
+#include <ccnx/transport/transport_rta/components/component_Testing.h>
+
+#include <ccnx/transport/transport_rta/config/config_ProtocolStack.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#define MAX_STACK_DEPTH 10
+
+#ifndef DEBUG_OUTPUT
+#define DEBUG_OUTPUT 0
+#endif
+
+const char *RtaComponentNames[LAST_COMPONENT] =
+{
+ "API", // 0
+ "FC_NONE",
+ "FC_VEGAS",
+ "FC_PIPELINE",
+ "VERIFY_NONE", // 4
+ "VERIFY_ENUMERATED",
+ "VERIFY_LOCATOR",
+ "CODEC_NONE",
+ NULL, // 8
+ "CODEC_TLV",
+ "CODEC_CCNB",
+ "CODE_FLAN",
+ NULL, // 12
+ "FWD_LOCAL",
+ "FWD_FLAN",
+ "FWD_CCND", // 15
+ "TESTING_UPPER",
+ "TESTING_LOWER", // 17
+ "CCND_REGISTRAR",
+ "FWD_METIS"
+};
+
+struct protocol_stack {
+ int stack_id;
+
+ // used during configuration to indicate if configured
+ int config_codec;
+
+ RtaFramework *framework;
+
+ // They key value pairs passed to open. The api must
+ // keep this memory valid for as long as the connection is open
+ PARCJSON *params;
+
+ // the inter-component queues
+ unsigned component_count;
+ PARCEventQueuePair *queue_pairs[MAX_STACK_DEPTH];
+ RtaComponents components[MAX_STACK_DEPTH];
+
+ // queues assigned to components
+ struct component_queues {
+ PARCEventQueue *up;
+ PARCEventQueue *down;
+ } *component_queues[LAST_COMPONENT];
+ RtaComponentOperations component_ops[LAST_COMPONENT];
+ void *component_state[LAST_COMPONENT];
+
+ // stack-wide stats
+ RtaComponentStats *stack_stats[LAST_COMPONENT];
+
+
+ // state change events are disabled during initial setup and teardown
+ bool stateChangeEventsEnabled;
+};
+
+static void set_queue_pairs(RtaProtocolStack *stack, RtaComponents comp_type);
+static int configure_ApiConnector(RtaProtocolStack *stack, RtaComponents comp_type, RtaComponentOperations ops);
+static int configure_Component(RtaProtocolStack *stack, RtaComponents comp_type, RtaComponentOperations ops);
+static int configure_FwdConnector(RtaProtocolStack *stack, RtaComponents comp_type, RtaComponentOperations ops);
+
+// ========================================
+
+RtaFramework *
+rtaProtocolStack_GetFramework(RtaProtocolStack *stack)
+{
+ assertNotNull(stack, "called with null stack");
+ return stack->framework;
+}
+
+RtaProtocolStack *
+rtaProtocolStack_Create(RtaFramework *framework, PARCJSON *params, int stack_id)
+{
+ RtaProtocolStack *stack = parcMemory_AllocateAndClear(sizeof(RtaProtocolStack));
+ assertNotNull(stack, "%9" PRIu64 " parcMemory_AllocateAndClear returned NULL\n",
+ rtaFramework_GetTicks(stack->framework));
+
+ stack->stateChangeEventsEnabled = false;
+
+ stack->params = parcJSON_Copy(params);
+
+ assertNotNull(stack->params, "SYSTEM key is NULL in params");
+
+ assertNotNull(framework, "Parameter framework may not be null");
+
+ stack->framework = framework;
+ stack->stack_id = stack_id;
+
+ // create all the buffer pairs
+ for (int i = 0; i < MAX_STACK_DEPTH; i++) {
+ stack->queue_pairs[i] = parcEventQueue_CreateConnectedPair(rtaFramework_GetEventScheduler(stack->framework));
+
+ assertNotNull(stack->queue_pairs[i], "parcEventQueue_CreateConnectedPair returned NULL index %d", i);
+ if (stack->queue_pairs[i] == NULL) {
+ for (int j = 0; j < i; j++) {
+ parcEventQueue_DestroyConnectedPair(&(stack->queue_pairs[j]));
+ }
+
+ parcMemory_Deallocate((void **) &stack);
+ return NULL;
+ }
+
+ // set them all to normal priority. The command port is high priority. External buffes are low priority.
+ parcEventQueue_SetPriority(parcEventQueue_GetConnectedUpQueue(stack->queue_pairs[i]), PARCEventPriority_Normal);
+ parcEventQueue_SetPriority(parcEventQueue_GetConnectedDownQueue(stack->queue_pairs[i]), PARCEventPriority_Normal);
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s create buffer pair %p <-> %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(stack)),
+ __func__,
+ (void *) parcEventQueue_GetConnectedUpQueue(stack->queue_pairs[i]),
+ (void *) parcEventQueue_GetConnectedDownQueue(stack->queue_pairs[i]));
+ }
+ }
+
+ for (int i = 0; i < LAST_COMPONENT; i++) {
+ stack->stack_stats[i] = rtaComponentStats_Create(NULL, i);
+ }
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s created stack %d at %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(stack)),
+ __func__,
+ stack_id,
+ (void *) stack);
+ }
+
+ stack->stateChangeEventsEnabled = true;
+
+ return stack;
+}
+
+/**
+ * Opens a connection inside the protocol stack: it calls open() on each component.
+ *
+ * Returns 0 on success, -1 on error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int
+rtaProtocolStack_Open(RtaProtocolStack *stack, RtaConnection *connection)
+{
+ assertNotNull(stack, "called with null stack\n");
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s stack_id %d opening conn %p api_fd %d\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(stack)),
+ __func__,
+ stack->stack_id,
+ (void *) connection, rtaConnection_GetApiFd(connection));
+ }
+
+ // call all the opens, except the api
+
+ // need to disable events during creation to avoid calling the event notifier
+ // of a component before the component sees the "open" call for this connection
+ stack->stateChangeEventsEnabled = false;
+ for (int i = 0; i < stack->component_count; i++) {
+ RtaComponents comp = stack->components[i];
+ if (stack->component_ops[comp].open != NULL &&
+ stack->component_ops[comp].open(connection) != 0) {
+ fprintf(stderr, "%s component %d failed open\n", __func__, i);
+ abort();
+ return -1;
+ }
+ }
+ stack->stateChangeEventsEnabled = true;
+
+ return 0;
+}
+
+/*
+ * Closes a connection but does not touch stack->connection_head
+ */
+static int
+internal_Stack_Close(RtaProtocolStack *stack, RtaConnection *conn)
+{
+ int i;
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s stack_id %d closing stack %p conn %p\n",
+ rtaFramework_GetTicks(rtaConnection_GetFramework(conn)),
+ __func__,
+ stack->stack_id,
+ (void *) stack,
+ (void *) conn);
+ }
+
+ rtaConnection_SetState(conn, CONN_CLOSED);
+
+ // call all the opens
+ for (i = 0; i < stack->component_count; i++) {
+ RtaComponents comp = stack->components[i];
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s calling close for %s\n",
+ rtaFramework_GetTicks(rtaConnection_GetFramework(conn)), __func__, RtaComponentNames[comp]);
+ }
+
+ if (stack->component_ops[comp].close != NULL &&
+ stack->component_ops[comp].close(conn) != 0) {
+ fprintf(stderr, "%s component %d failed open\n", __func__, i);
+ abort();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Calls the close() function of each component in the protocol stack.
+ *
+ * This is typically called from inside the API connector when it processes
+ * a CLOSE json message.
+ * Returns 0 success, -1 error.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int
+rtaProtocolStack_Close(RtaProtocolStack *stack, RtaConnection *conn)
+{
+ assertNotNull(stack, "called with null stack\n");
+ assertNotNull(conn, "called with null connection\n");
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s stack_id %d stack %p conn %p\n",
+ rtaFramework_GetTicks(rtaConnection_GetFramework(conn)),
+ __func__,
+ stack->stack_id,
+ (void *) stack,
+ (void *) conn);
+ }
+
+
+ internal_Stack_Close(stack, conn);
+
+ return 0;
+}
+
+/**
+ * Calls the release() function of all components.
+ * Drains all the component queues.
+ *
+ * This is called from rtaFramework_DestroyStack, who is responsible for closing
+ * all the connections in it before calling this.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+rtaProtocolStack_Destroy(RtaProtocolStack **stackPtr)
+{
+ RtaProtocolStack *stack;
+
+ assertNotNull(stackPtr, "%s called with null pointer to stack\n", __func__);
+
+ stack = *stackPtr;
+ assertNotNull(stack, "%s called with null stack dereference\n", __func__);
+
+ if (DEBUG_OUTPUT) {
+ printf("%s stack_id %d destroying stack %p\n",
+ __func__,
+ stack->stack_id,
+ (void *) stack);
+ }
+
+ stack->stateChangeEventsEnabled = false;
+
+ // call all the release functions
+ for (int i = 0; i < stack->component_count; i++) {
+ RtaComponents comp = stack->components[i];
+ if (stack->component_ops[comp].release != NULL &&
+ stack->component_ops[comp].release(stack) != 0) {
+ fprintf(stderr, "%s component %d failed release\n", __func__, i);
+ abort();
+ }
+ }
+
+ for (int i = 0; i < MAX_STACK_DEPTH; i++) {
+ TransportMessage *tm;
+ while ((tm = rtaComponent_GetMessage(parcEventQueue_GetConnectedUpQueue(stack->queue_pairs[i]))) != NULL) {
+ assertFalse(1, "%s we should never execute the body, it should just drain\n", __func__);
+ }
+
+ while ((tm = rtaComponent_GetMessage(parcEventQueue_GetConnectedDownQueue(stack->queue_pairs[i]))) != NULL) {
+ assertFalse(1, "%s we should never execute the body, it should just drain\n", __func__);
+ }
+
+ if (DEBUG_OUTPUT) {
+ printf("%9" PRIu64 " %s destroy buffer pair %p <-> %p\n",
+ rtaFramework_GetTicks(rtaProtocolStack_GetFramework(stack)),
+ __func__,
+ (void *) parcEventQueue_GetConnectedUpQueue(stack->queue_pairs[i]),
+ (void *) parcEventQueue_GetConnectedDownQueue(stack->queue_pairs[i]));
+ }
+
+ parcEventQueue_DestroyConnectedPair(&(stack->queue_pairs[i]));
+ }
+
+ for (int i = 0; i < LAST_COMPONENT; i++) {
+ if (stack->component_queues[i]) {
+ parcMemory_Deallocate((void **) &(stack->component_queues[i]));
+ }
+ }
+
+ for (int i = 0; i < LAST_COMPONENT; i++) {
+ rtaComponentStats_Destroy(&stack->stack_stats[i]);
+ }
+
+
+ parcJSON_Release(&stack->params);
+ memset(stack, 0, sizeof(RtaProtocolStack));
+
+ parcMemory_Deallocate((void **) &stack);
+ *stackPtr = NULL;
+}
+
+
+PARCEventQueue *
+rtaProtocolStack_GetPutQueue(RtaProtocolStack *stack, RtaComponents component, RtaDirection direction)
+{
+ assertNotNull(stack, "%s called with null stack\n", __func__);
+
+ if (direction == RTA_UP) {
+ return stack->component_queues[component]->up;
+ } else {
+ return stack->component_queues[component]->down;
+ }
+}
+
+
+/**
+ * Look up the symbolic name of the queue. Do not free the return.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *
+rtaProtocolStack_GetQueueName(RtaProtocolStack *stack, PARCEventQueue *queue)
+{
+ int component;
+ for (component = 0; component <= LAST_COMPONENT; component++) {
+ if (stack->component_queues[component]) {
+ if (stack->component_queues[component]->up == queue) {
+ return RtaComponentNames[component];
+ }
+ if (stack->component_queues[component]->down == queue) {
+ return RtaComponentNames[component];
+ }
+ }
+ }
+ trapUnexpectedState("Could not find queue %p in stack %p", (void *) queue, (void *) stack);
+}
+
+// =================================================
+// =================================================
+
+static RtaComponents
+getComponentTypeFromName(const char *name)
+{
+ int i;
+
+ if (name == NULL) {
+ return UNKNOWN_COMPONENT;
+ }
+
+ for (i = 0; i < LAST_COMPONENT; i++) {
+ if (RtaComponentNames[i] != NULL) {
+ if (strncasecmp(RtaComponentNames[i], name, 16) == 0) {
+ return (RtaComponents) i;
+ }
+ }
+ }
+ return UNKNOWN_COMPONENT;
+}
+
+
+/**
+ * Calls the confguration routine for each component in the stack
+ *
+ * Builds an array list of everything in the JSON configuration, then
+ * calls its configuation routine.
+ *
+ * The connecting event queues are disabled at this point.
+ *
+ * @param [in,out] stack The Protocol Stack to operate on
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+rtaProtocolStack_ConfigureComponents(RtaProtocolStack *stack)
+{
+ PARCArrayList *componentNameList;
+ componentNameList = protocolStack_GetComponentNameArray(stack->params);
+ assertTrue(parcArrayList_Size(componentNameList) < MAX_STACK_DEPTH,
+ "Too many components in a stack size %zu\n",
+ parcArrayList_Size(componentNameList));
+
+
+ for (int i = 0; i < parcArrayList_Size(componentNameList); i++) {
+ // match it to a component type
+ const char *comp_name = parcArrayList_Get(componentNameList, i);
+ RtaComponents comp_type = getComponentTypeFromName(comp_name);
+
+ // this could be sped up slightly by putting the ops structures
+ // in an array
+ switch (comp_type) {
+ case API_CONNECTOR:
+ configure_ApiConnector(stack, comp_type, api_ops);
+ break;
+
+ case FC_NONE:
+ trapIllegalValue(comp_type, "Null flowcontroller no longer supported");
+ break;
+ case FC_VEGAS:
+ configure_Component(stack, comp_type, flow_vegas_ops);
+ break;
+ case FC_PIPELINE:
+ abort();
+ break;
+
+ case CODEC_NONE:
+ trapIllegalValue(comp_type, "Null codec no longer supported");
+ break;
+ case CODEC_TLV:
+ configure_Component(stack, comp_type, codec_tlv_ops);
+ break;
+
+ case FWD_NONE:
+ abort();
+ break;
+ case FWD_LOCAL:
+ configure_FwdConnector(stack, comp_type, fwd_local_ops);
+ break;
+
+ case FWD_METIS:
+ configure_FwdConnector(stack, comp_type, fwd_metis_ops);
+ break;
+
+ case TESTING_UPPER:
+ // fallthrough
+ case TESTING_LOWER:
+ configure_Component(stack, comp_type, testing_null_ops);
+ break;
+
+
+ default:
+ fprintf(stderr, "%s unsupported component type %s\n", __func__, comp_name);
+ abort();
+ }
+ }
+ parcArrayList_Destroy(&componentNameList);
+}
+
+static bool
+rtaProtocolStack_InitializeComponents(RtaProtocolStack *stack)
+{
+ // Call all the inits
+ for (int i = 0; i < LAST_COMPONENT; i++) {
+ int res = 0;
+ if (stack->component_ops[i].init != NULL) {
+ res = stack->component_ops[i].init(stack);
+ }
+
+ if (res != 0) {
+ fprintf(stderr, "%s opener for layer %d failed\n", __func__, i);
+ trapUnrecoverableState("Error Initializing the components")
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * Enables events on all the queues between components
+ *
+ * Enables events on each queue.
+ *
+ * @param [in,out] stack The PRotocol stack
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+rtaProtocolStack_EnableComponentQueues(RtaProtocolStack *stack)
+{
+ // enable all the events on intermediate queues
+ for (int i = 0; i < stack->component_count; i++) {
+ RtaComponents component = stack->components[i];
+ PARCEventQueue *upQueue = stack->component_queues[component]->up;
+ if (upQueue != NULL) {
+ parcEventQueue_Enable(upQueue, PARCEventType_Read);
+ }
+
+ PARCEventQueue *downQueue = stack->component_queues[component]->down;
+ if (downQueue != NULL) {
+ parcEventQueue_Enable(downQueue, PARCEventType_Read);
+ }
+ }
+}
+
+/*
+ * Called from transportRta_Open()
+ *
+ * Returns 0 for success, -1 on error (connection not made)
+ */
+int
+rtaProtocolStack_Configure(RtaProtocolStack *stack)
+{
+ assertNotNull(stack, "%s called with null stack\n", __func__);
+
+ rtaProtocolStack_ConfigureComponents(stack);
+
+ bool initSuccess = rtaProtocolStack_InitializeComponents(stack);
+ if (!initSuccess) {
+ return -1;
+ }
+
+ rtaProtocolStack_EnableComponentQueues(stack);
+
+ return 0;
+}
+
+/*
+ * Domain is the top-level key, e.g. SYSTEM or USER
+ */
+PARCJSON *
+rtaProtocolStack_GetParam(RtaProtocolStack *stack, const char *domain, const char *key)
+{
+ assertNotNull(stack, "%s called with null stack\n", __func__);
+ assertNotNull(domain, "%s called with null domain\n", __func__);
+ assertNotNull(key, "%s called with null key\n", __func__);
+
+ PARCJSONValue *value = parcJSON_GetValueByName(stack->params, domain);
+ assertNotNull(value, "Did not find domain %s in protocol stack parameters", domain);
+ if (value == NULL) {
+ return NULL;
+ }
+ PARCJSON *domainJson = parcJSONValue_GetJSON(value);
+
+ value = parcJSON_GetValueByName(domainJson, key);
+ assertNotNull(value, "Did not find key %s in protocol stack parameters", key);
+ return parcJSONValue_GetJSON(value);
+}
+
+unsigned
+rtaProtocolStack_GetNextConnectionId(RtaProtocolStack *stack)
+{
+ assertNotNull(stack, "Parameter stack must be a non-null RtaProtocolStack pointer.");
+ return rtaFramework_GetNextConnectionId(stack->framework);
+}
+
+RtaComponentStats *
+rtaProtocolStack_GetStats(const RtaProtocolStack *stack, RtaComponents type)
+{
+ assertTrue(type < LAST_COMPONENT, "invalid type %d\n", type);
+ return stack->stack_stats[type];
+}
+
+static void
+printSingleTuple(FILE *file, const struct timeval *timeval, const RtaProtocolStack *stack, RtaComponents componentType, RtaComponentStatType stat)
+{
+ RtaComponentStats *stats = rtaProtocolStack_GetStats(stack, componentType);
+
+ fprintf(file, "{ \"stackId\" : %d, \"component\" : \"%s\", \"name\" : \"%s\", \"value\" : %" PRIu64 ", \"timeval\" : %ld.%06u }\n",
+ stack->stack_id,
+ RtaComponentNames[componentType],
+ rtaComponentStatType_ToString(stat),
+ rtaComponentStats_Get(stats, stat),
+ timeval->tv_sec,
+ (unsigned) timeval->tv_usec
+ );
+}
+
+PARCArrayList *
+rtaProtocolStack_GetStatistics(const RtaProtocolStack *stack, FILE *file)
+{
+ PARCArrayList *list = parcArrayList_Create(NULL);
+
+ struct timeval timeval;
+ gettimeofday(&timeval, NULL);
+
+ // This does not fill in the array list
+ for (int componentIndex = 0; componentIndex < stack->component_count; componentIndex++) {
+ RtaComponents componentType = stack->components[componentIndex];
+ printSingleTuple(file, &timeval, stack, componentType, STATS_OPENS);
+ printSingleTuple(file, &timeval, stack, componentType, STATS_CLOSES);
+ printSingleTuple(file, &timeval, stack, componentType, STATS_UPCALL_IN);
+ printSingleTuple(file, &timeval, stack, componentType, STATS_UPCALL_OUT);
+ printSingleTuple(file, &timeval, stack, componentType, STATS_DOWNCALL_IN);
+ printSingleTuple(file, &timeval, stack, componentType, STATS_DOWNCALL_OUT);
+ }
+
+ return list;
+}
+
+
+// =============================================
+
+static void
+set_queue_pairs(RtaProtocolStack *stack, RtaComponents comp_type)
+{
+ //PARCEventQueuePair *component_queues[LAST_COMPONENT];
+ // Save references to the OUTPUT queues used by a specific component.
+ if (stack->component_queues[comp_type] == NULL) {
+ stack->component_queues[comp_type] = parcMemory_AllocateAndClear(sizeof(struct component_queues));
+ }
+
+ stack->component_queues[comp_type]->up =
+ parcEventQueue_GetConnectedUpQueue(stack->queue_pairs[stack->component_count - 1]);
+
+ stack->component_queues[comp_type]->down =
+ parcEventQueue_GetConnectedDownQueue(stack->queue_pairs[stack->component_count]);
+
+ // Set callbacks on the INPUT queues read by a specific component
+ parcEventQueue_SetCallbacks(stack->component_queues[comp_type]->up,
+ stack->component_ops[comp_type].downcallRead,
+ NULL,
+ stack->component_ops[comp_type].downcallEvent,
+ (void *) stack);
+
+ parcEventQueue_SetCallbacks(stack->component_queues[comp_type]->down,
+ stack->component_ops[comp_type].upcallRead,
+ NULL,
+ stack->component_ops[comp_type].upcallEvent,
+ (void *) stack);
+}
+
+
+static int
+configure_ApiConnector(RtaProtocolStack *stack, RtaComponents comp_type, RtaComponentOperations ops)
+{
+ if (stack->component_queues[comp_type] == NULL) {
+ stack->component_queues[comp_type] = parcMemory_AllocateAndClear(sizeof(struct component_queues));
+ }
+
+ assertNotNull(stack->component_queues[comp_type], "called with null component_queue");
+ assertNotNull(stack->queue_pairs[stack->component_count], "called with null queue_pair");
+
+ // This wires the bottom half of the API Connector to the streams.
+ // It does not do the top half, which is in the connector's INIT
+
+ stack->components[stack->component_count] = comp_type;
+ stack->component_ops[comp_type] = ops;
+
+ stack->component_queues[comp_type]->down =
+ parcEventQueue_GetConnectedDownQueue(stack->queue_pairs[stack->component_count]);
+
+ parcEventQueue_SetCallbacks(stack->component_queues[comp_type]->down,
+ stack->component_ops[comp_type].upcallRead,
+ NULL,
+ stack->component_ops[comp_type].upcallEvent,
+ (void *) stack);
+
+ stack->component_count++;
+ return 0;
+}
+
+static int
+configure_Component(RtaProtocolStack *stack, RtaComponents comp_type, RtaComponentOperations ops)
+{
+ stack->component_ops[comp_type] = ops;
+ stack->components[stack->component_count] = comp_type;
+ set_queue_pairs(stack, comp_type);
+ stack->component_count++;
+ return 0;
+}
+
+
+static int
+configure_FwdConnector(RtaProtocolStack *stack, RtaComponents comp_type, RtaComponentOperations ops)
+{
+ stack->component_ops[comp_type] = ops;
+ stack->components[stack->component_count] = comp_type;
+
+ // We only set the upcall buffers. The down buffers
+ // are controlled by the forwarder connector
+ if (stack->component_queues[comp_type] == NULL) {
+ stack->component_queues[comp_type] = parcMemory_AllocateAndClear(sizeof(struct component_queues));
+ }
+
+ stack->component_queues[comp_type]->up =
+ parcEventQueue_GetConnectedUpQueue(stack->queue_pairs[stack->component_count - 1]);
+
+ parcEventQueue_SetCallbacks(stack->component_queues[comp_type]->up,
+ stack->component_ops[comp_type].downcallRead,
+ NULL,
+ stack->component_ops[comp_type].downcallEvent,
+ (void *) stack);
+
+ stack->component_count++;
+ return 0;
+}
+
+int
+rtaProtocolStack_GetStackId(RtaProtocolStack *stack)
+{
+ return stack->stack_id;
+}
+
+void
+rtaProtocolStack_ConnectionStateChange(RtaProtocolStack *stack, void *connection)
+{
+ if (stack->stateChangeEventsEnabled) {
+ for (int componentIndex = 0; componentIndex < stack->component_count; componentIndex++) {
+ RtaComponents componentType = stack->components[componentIndex];
+ if (stack->component_ops[componentType].stateChange != NULL) {
+ stack->component_ops[componentType].stateChange(connection);
+ }
+ }
+ }
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ProtocolStack.h b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ProtocolStack.h
new file mode 100644
index 00000000..df09c23f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/rta_ProtocolStack.h
@@ -0,0 +1,379 @@
+/*
+ * 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_ProtocolStack.h
+ * @brief A set of connectors and components
+ *
+ * In a Ready To Assemble transport, individual pieces are called connectors
+ * and components. A connector attaches to the API library at the top and
+ * to the forwarder at the bottom. In between the connectors are components.
+ *
+ * One set of connectors and components is called a protocol stack.
+ *
+ * A ProtocolStack defines a set of Components linked by bidirectional
+ * queues. A ProtocolStack is defined by the KeyValue set passed to
+ * the Transport. The hash of the KeyValue set selects the protocol stack.
+ * If the Transport sees a new hash, it creates a new protocol stack
+ * via ProtocolStack_Create().
+ *
+ * Each API connection calls _Open, which will return a new RtaConnection
+ * pointer. The Transport gives the API an "api_fd", which the Transport
+ * translates to the RtaConnection.
+ *
+ * A protocol stack is implemented as a set of queue pairs between components.
+ * There is a fixed sized array called queue_pairs[MAX_STACK_DEPTH]. The
+ * queue_pairs[i].pair[RTA_DOWN] end attaches to the upper component. RTA_DOWN
+ * indicates the direction of travel for a write. queue_pairs[i].pair[RTA_UP]
+ * attaches to the lower component.
+ *
+ * A component only knows its identity (see components.h). For example, the
+ * TLV codec is called CODEC_TLV, and that is the only identity it know. It does
+ * not know the identity of the pieces above or below it.
+ *
+ * Therefore, when a component calls protocolStack_GetPutQ(stack, CODEC_TLV, RTA_DOWN),
+ * it is asking for the queue to write to in the DOWN direction. This means that
+ * we should keep an index by the component name, not by the queue_pairs[] array.
+ * Thus, we keep a component_queues[] array that is indexed by the component name.
+ *
+ * Let's say our stack is API_CONNECTOR, FC_NULL, VERIFY_NULL, CODEC_TLV, FWD_LOCAL.
+ * The picture is like this:
+ *
+ * @code
+ * |
+ * * <- api_connector managed queue
+ * API_CONNECTOR
+ * * <- queue_pair[0].pair[DOWN] <- component_queue[API_CONNECTOR].pair[DOWN]
+ * |
+ * * <- queue_pair[0].pair[UP] <- component_queue[FC_NULL].pair[UP]
+ * FC_NULL
+ * * <- queue_pair[1].pair[DOWN] <- component_queue[FC_NULL].pair[DOWN]
+ * |
+ * * <- queue_pair[1].pair[UP] <- component_queue[VERIFY_NULL].pair[UP]
+ * VERIFY_NULL
+ * * <- queue_pair[2].pair[DOWN] <- component_queue[VERIFY_NULL].pair[DOWN]
+ * |
+ * * <- queue_pair[2].pair[UP] <- component_queue[CODEC_TLV].pair[UP]
+ * CODEC_TLV
+ * * <- queue_pair[3].pair[DOWN] <- component_queue[CODEC_TLV].pair[DOWN]
+ * |
+ * * <- queue_pair[3].pair[UP] <- component_queue[FWD_LOCAL].pair[UP]
+ * FWD_LOCAL
+ * * <- fwd_local managed connection
+ * |
+ * @endcode
+ *
+ * Each component also has a pair of callbacks, one for reading messages flowing down
+ * the stack and one for reading messages flowing up the stack. These are called
+ * "downcall_read" for reading messages flowing down and "upcall_read" for messages
+ * flowing up.
+ *
+ * Recall that the direction attributes UP and DOWN in the queues are in terms
+ * of WRITES, therefore the directions are opposite for reads. A component's
+ * downcall_read will read from component_queue[X].pair[UP].
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#ifndef Libccnx_rta_ProtocolStack_h
+#define Libccnx_rta_ProtocolStack_h
+
+#include <parc/algol/parc_ArrayList.h>
+
+#include <parc/algol/parc_EventQueue.h>
+
+#include <ccnx/transport/transport_rta/core/rta_ComponentStats.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework.h>
+#include <ccnx/transport/transport_rta/core/components.h>
+#include <ccnx/transport/transport_rta/core/rta_ComponentQueue.h>
+#include <ccnx/transport/transport_rta/commands/rta_Command.h>
+
+struct rta_connection;
+struct component_queue;
+
+struct protocol_stack;
+typedef struct protocol_stack RtaProtocolStack;
+
+/**
+ * Used to assign unique connection id to sockets. This is just
+ * for internal tracking, its not a descriptor.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] stack <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+unsigned rtaProtocolStack_GetNextConnectionId(RtaProtocolStack *stack);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] framework <#description#>
+ * @param [in] params <#description#>
+ * @param [in] stack_id <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+RtaProtocolStack *rtaProtocolStack_Create(RtaFramework *framework, PARCJSON *params, int stack_id);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] stack <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+int rtaProtocolStack_Configure(RtaProtocolStack *stack);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] stack <#description#>
+ * @param [in] component <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void *rtaProtocolStack_GetPrivateData(RtaProtocolStack *stack, RtaComponents component);
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] stack <#description#>
+ * @param [in] component <#description#>
+ * @param [in] private <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void rtaProtocolStack_SetPrivateData(RtaProtocolStack *stack, RtaComponents component, void *private);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] stack <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+RtaFramework *rtaProtocolStack_GetFramework(RtaProtocolStack *stack);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+int rtaProtocolStack_GetStackId(RtaProtocolStack *stack);
+
+/**
+ * Opens a connection inside the protocol stack: it calls open() on each component.
+ *
+ * Returns 0 on success, -1 on error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int rtaProtocolStack_Open(RtaProtocolStack *, struct rta_connection *connection);
+
+/**
+ *
+ * 0 success, -1 error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int rtaProtocolStack_Close(RtaProtocolStack *, struct rta_connection *conn);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void rtaProtocolStack_Destroy(RtaProtocolStack **stack);
+
+/**
+ * Return the queue used for output for a component in a given direction
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCEventQueue *rtaProtocolStack_GetPutQueue(RtaProtocolStack *stack,
+ RtaComponents component,
+ RtaDirection direction);
+
+/**
+ * <#One Line Description#>
+ *
+ * Domain is the top-level key, e.g. SYSTEM or USER
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+PARCJSON *rtaProtocolStack_GetParam(RtaProtocolStack *stack, const char *domain, const char *key);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+RtaComponentStats *rtaProtocolStack_GetStats(const RtaProtocolStack *stack, RtaComponents type);
+
+/**
+ * <#OneLineDescription#>
+ *
+ * <#Discussion#>
+ *
+ * @param stack
+ * @param file
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCArrayList *rtaProtocolStack_GetStatistics(const RtaProtocolStack *stack, FILE *file);
+
+/**
+ * Look up the symbolic name of the queue. Do not free the return.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *rtaProtocolStack_GetQueueName(RtaProtocolStack *stack, PARCEventQueue *queue);
+
+/**
+ * A state event occured on the given connection, let all the components know.
+ *
+ * A state changed occured (UP, DOWN, PAUSE, or flow control), notify all the components
+ *
+ * @param [in] connection The RtaConnection.
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void rtaProtocolStack_ConnectionStateChange(RtaProtocolStack *stack, void *connection);
+#endif
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/.gitignore b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/.gitignore
new file mode 100644
index 00000000..8763938d
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/.gitignore
@@ -0,0 +1,10 @@
+test_rta_Component
+test_rta_Connection
+test_rta_Framework_NonThreaded
+test_rta_Framework_Services
+test_rta_Framework_Threaded
+test_rta_ProtocolStack
+test_rta_Logger
+test_rta_Stats
+output.txt
+core
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/CMakeLists.txt b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/CMakeLists.txt
new file mode 100644
index 00000000..b57c2afd
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_rta_ConnectionTable
+ test_rta_Framework
+ test_rta_Framework_Commands
+ test_rta_Component
+ test_rta_Connection
+ test_rta_Framework_NonThreaded
+ test_rta_Framework_Services
+ test_rta_Framework_Threaded
+ test_rta_Logger
+ test_rta_ProtocolStack
+ test_rta_ComponentStats
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Component.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Component.c
new file mode 100644
index 00000000..a1de01bf
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Component.c
@@ -0,0 +1,247 @@
+/*
+ * 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.
+ */
+
+/**
+ * Create a non-threaded framework to test comopnent functions.
+ *
+ */
+#define DEBUG_OUTPUT 1
+#include "../rta_Component.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/config/config_All.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_Commands.c>
+#include <ccnx/transport/test_tools/traffic_tools.h>
+
+#include <sys/socket.h>
+#include <errno.h>
+
+#define PAIR_OTHER 0
+#define PAIR_TRANSPORT 1
+
+typedef struct test_data {
+ PARCRingBuffer1x1 *commandRingBuffer;
+ PARCNotifier *commandNotifier;
+
+ int api_fds[2];
+ RtaFramework *framework;
+ RtaProtocolStack *stack;
+ RtaConnection *connection;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ int error = socketpair(AF_UNIX, SOCK_STREAM, 0, data->api_fds);
+ assertFalse(error, "Error creating socket pair: (%d) %s", errno, strerror(errno));
+
+ data->commandRingBuffer = parcRingBuffer1x1_Create(128, NULL);
+ data->commandNotifier = parcNotifier_Create();
+ data->framework = rtaFramework_Create(data->commandRingBuffer, data->commandNotifier);
+
+ assertNotNull(data->framework, "rtaFramework_Create returned null");
+
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+ apiConnector_ProtocolStackConfig(stackConfig);
+ testingLower_ProtocolStackConfig(stackConfig);
+ protocolStack_ComponentsConfigArgs(stackConfig, apiConnector_GetName(), testingLower_GetName(), NULL);
+
+ rtaFramework_NonThreadedStepCount(data->framework, 10);
+
+ int stackId = 1;
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stackId, stackConfig);
+ _rtaFramework_ExecuteCreateStack(data->framework, createStack);
+ rtaCommandCreateProtocolStack_Release(&createStack);
+
+ rtaFramework_NonThreadedStepCount(data->framework, 10);
+ data->stack = (rtaFramework_GetProtocolStackByStackId(data->framework, stackId))->stack;
+
+ CCNxConnectionConfig *connConfig = ccnxConnectionConfig_Create();
+ apiConnector_ConnectionConfig(connConfig);
+
+ tlvCodec_ConnectionConfig(connConfig);
+
+ testingLower_ConnectionConfig(connConfig);
+
+ RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(stackId,
+ data->api_fds[PAIR_OTHER],
+ data->api_fds[PAIR_TRANSPORT],
+ ccnxConnectionConfig_GetJson(connConfig));
+
+ rtaFramework_NonThreadedStepCount(data->framework, 10);
+ _rtaFramework_ExecuteOpenConnection(data->framework, openConnection);
+ rtaCommandOpenConnection_Release(&openConnection);
+
+ rtaFramework_NonThreadedStepCount(data->framework, 10);
+ data->connection = rtaConnectionTable_GetByApiFd(data->framework->connectionTable, data->api_fds[PAIR_OTHER]);
+
+ ccnxConnectionConfig_Destroy(&connConfig);
+ ccnxStackConfig_Release(&stackConfig);
+
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ rtaFramework_Teardown(data->framework);
+
+ parcRingBuffer1x1_Release(&data->commandRingBuffer);
+ parcNotifier_Release(&data->commandNotifier);
+ rtaFramework_Destroy(&data->framework);
+
+ close(data->api_fds[0]);
+ close(data->api_fds[1]);
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(rta_Component)
+{
+ // 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_Component)
+{
+ 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_Component)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaComponent_GetOutputQueue);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaComponent_PutMessage_ClosedConnection);
+ LONGBOW_RUN_TEST_CASE(Global, rtaComponent_PutMessage_OpenConnection);
+}
+
+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, rtaComponent_GetOutputQueue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCEventQueue *queue = rtaComponent_GetOutputQueue(data->connection, API_CONNECTOR, RTA_DOWN);
+ assertNotNull(queue, "Got null queue for API_CONNECTOR DOWN queue");
+}
+
+LONGBOW_TEST_CASE(Global, rtaComponent_PutMessage_ClosedConnection)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ rtaConnection_SetState(data->connection, CONN_CLOSED);
+
+ // Create the TransportMessage to put on the queue
+ TransportMessage *tm = trafficTools_CreateTransportMessageWithDictionaryControl(data->connection, CCNxTlvDictionary_SchemaVersion_V1);
+
+ // Send it down from the API connector to the Testing Lower component
+ PARCEventQueue *outputQueue = rtaComponent_GetOutputQueue(data->connection, API_CONNECTOR, RTA_DOWN);
+
+ int success = rtaComponent_PutMessage(outputQueue, tm);
+ assertFalse(success, "Error putting message on API Connector's down queue");
+
+ // check that we got it
+ PARCEventQueue *inputQueue = rtaComponent_GetOutputQueue(data->connection, TESTING_LOWER, RTA_UP);
+
+ TransportMessage *test_tm = rtaComponent_GetMessage(inputQueue);
+ assertNull(test_tm, "Should have returned NULL on a closed connection");
+
+ // The transport message was destroyed by PutMessage because the connection
+ // was closed. Don't need to destroy the transport message.
+
+ // set state back to OPEN so the connection is properly disposed of
+ rtaConnection_SetState(data->connection, CONN_OPEN);
+}
+
+LONGBOW_TEST_CASE(Global, rtaComponent_PutMessage_OpenConnection)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // Create the TransportMessage to put on the queue
+ TransportMessage *tm = trafficTools_CreateTransportMessageWithDictionaryControl(data->connection, CCNxTlvDictionary_SchemaVersion_V1);
+
+ // Send it down from the API connector to the Testing Lower component
+ PARCEventQueue *outputQueue = rtaComponent_GetOutputQueue(data->connection, API_CONNECTOR, RTA_DOWN);
+
+ int success = rtaComponent_PutMessage(outputQueue, tm);
+ assertTrue(success, "Error putting message on API Connector's down queue");
+
+ // check that we got it
+ PARCEventQueue *inputQueue = rtaComponent_GetOutputQueue(data->connection, TESTING_LOWER, RTA_UP);
+
+ TransportMessage *test_tm = rtaComponent_GetMessage(inputQueue);
+ assertTrue(test_tm == tm, "Got wrong message, got %p expected %p", (void *) test_tm, (void *) tm);
+
+ transportMessage_Destroy(&tm);
+}
+
+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_Component);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ComponentStats.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ComponentStats.c
new file mode 100644
index 00000000..1da0b4fc
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ComponentStats.c
@@ -0,0 +1,189 @@
+/*
+ * 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 "../rta_ComponentStats.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/config/config_All.h>
+
+#include <inttypes.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#define PAIR_OTHER 0
+#define PAIR_TRANSPORT 1
+
+#include <LongBow/unit-test.h>
+
+typedef struct test_data {
+ PARCRingBuffer1x1 *commandRingBuffer;
+ PARCNotifier *commandNotifier;
+
+ int api_fds[2];
+ RtaFramework *framework;
+ RtaProtocolStack *stack;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ int error = socketpair(AF_UNIX, SOCK_STREAM, 0, data->api_fds);
+ assertTrue(error == 0, "Error creating socket pair: (%d) %s", errno, strerror(errno));
+
+ data->commandRingBuffer = parcRingBuffer1x1_Create(128, NULL);
+ data->commandNotifier = parcNotifier_Create();
+ data->framework = rtaFramework_Create(data->commandRingBuffer, data->commandNotifier);
+ assertNotNull(data->framework, "rtaFramework_Create returned null");
+
+ rtaFramework_Start(data->framework);
+
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+ apiConnector_ProtocolStackConfig(stackConfig);
+ testingLower_ProtocolStackConfig(stackConfig);
+ protocolStack_ComponentsConfigArgs(stackConfig, apiConnector_GetName(), testingLower_GetName(), NULL);
+ data->stack = rtaProtocolStack_Create(data->framework, ccnxStackConfig_GetJson(stackConfig), 1);
+
+ ccnxStackConfig_Release(&stackConfig);
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ rtaProtocolStack_Destroy(&data->stack);
+
+ // blocks until done
+ rtaFramework_Shutdown(data->framework);
+
+ parcRingBuffer1x1_Release(&data->commandRingBuffer);
+ parcNotifier_Release(&data->commandNotifier);
+ rtaFramework_Destroy(&data->framework);
+
+ close(data->api_fds[0]);
+ close(data->api_fds[1]);
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(rta_Stats)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(rta_Stats)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_Stats)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, stats_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, stats_Dump);
+ LONGBOW_RUN_TEST_CASE(Global, stats_Get);
+ LONGBOW_RUN_TEST_CASE(Global, stats_Increment);
+}
+
+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, stats_Create_Destroy)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaComponentStats *stats = rtaComponentStats_Create(data->stack, API_CONNECTOR);
+
+ assertNotNull(stats, "Got null stats from rtaComponentStats_Create");
+ assertTrue(stats->stack == data->stack,
+ "Bad stack pointer, got %p expected %p",
+ (void *) stats->stack, (void *) data->stack);
+
+ rtaComponentStats_Destroy(&stats);
+}
+
+LONGBOW_TEST_CASE(Global, stats_Dump)
+{
+ for (int i = 0; i < STATS_LAST; i++) {
+ char *test = rtaComponentStatType_ToString(i);
+ assertNotNull(test, "Got null string for stat type %d", i);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, stats_Get)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaComponentStats *stats = rtaComponentStats_Create(data->stack, API_CONNECTOR);
+
+ for (int i = 0; i < STATS_LAST; i++) {
+ // set each stat to a value
+ uint64_t value = i + 5;
+ stats->stats[i] = value;
+
+ uint64_t counter = stats->stats[i];
+ assertTrue(counter == value, "Counter %d wrong value, got %" PRIu64 " expected %" PRIu64, i, counter, value);
+ }
+
+ rtaComponentStats_Destroy(&stats);
+}
+
+LONGBOW_TEST_CASE(Global, stats_Increment)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaComponentStats *stats = rtaComponentStats_Create(data->stack, API_CONNECTOR);
+
+ for (int i = 0; i < STATS_LAST; i++) {
+ rtaComponentStats_Increment(stats, (RtaComponentStatType) i);
+ }
+
+ // now make sure they are all "1"
+ for (int i = 0; i < STATS_LAST; i++) {
+ uint64_t counter = stats->stats[i];
+ assertTrue(counter == 1, "Counter %d wrong value, got %" PRIu64 "expected 1", i, counter);
+ }
+
+ rtaComponentStats_Destroy(&stats);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_Stats);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Connection.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Connection.c
new file mode 100644
index 00000000..4b80d7e1
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Connection.c
@@ -0,0 +1,82 @@
+/*
+ * 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 "../rta_Connection.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(rta_Connection)
+{
+ // 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_Connection)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_Connection)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
+
+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_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(rta_Connection);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ConnectionTable.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ConnectionTable.c
new file mode 100644
index 00000000..d77f47c0
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ConnectionTable.c
@@ -0,0 +1,309 @@
+/*
+ * 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 "../rta_ConnectionTable.c"
+#include "../rta_ProtocolStack.c"
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(rta_ConnectionTable)
+{
+ // 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(rta_ConnectionTable)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_ConnectionTable)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_AddConnection);
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_AddConnection_TooMany);
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_GetByApiFd);
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_GetByTransportFd);
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_RemoveByStack);
+}
+
+typedef struct test_data {
+ PARCRingBuffer1x1 *commandRingBuffer;
+ PARCNotifier *commandNotifier;
+
+ RtaFramework *framework;
+
+ // in some tests we use two protocol stacks
+ RtaProtocolStack *stack_a;
+ RtaProtocolStack *stack_b;
+} TestData;
+
+static RtaConnection *
+createConnection(RtaProtocolStack *stack, int api_fd, int transport_fd)
+{
+ // -------
+ // Create a connection to use in the table
+ PARCJSON *params = parcJSON_ParseString("{}");
+ RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(stack->stack_id, api_fd, transport_fd, params);
+
+ // Create a connection that goes in the connection table
+ RtaConnection *conn = rtaConnection_Create(stack, openConnection);
+ assertNotNull(conn, "Got null connection from rtaConnection_Create");
+
+ rtaCommandOpenConnection_Release(&openConnection);
+ parcJSON_Release(&params);
+ return conn;
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ // ---------------------------
+ // To test a connection table, we need to create a Framework and a Protocol stack
+
+ data->commandRingBuffer = parcRingBuffer1x1_Create(128, NULL);
+ data->commandNotifier = parcNotifier_Create();
+
+ data->framework = rtaFramework_Create(data->commandRingBuffer, data->commandNotifier);
+
+ // fake out a protocol stack
+ data->stack_a = parcMemory_AllocateAndClear(sizeof(RtaProtocolStack));
+ assertNotNull(data->stack_a, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(RtaProtocolStack));
+ data->stack_a->stack_id = 1;
+ data->stack_a->framework = data->framework;
+
+ // fake out a protocol stack
+ data->stack_b = parcMemory_AllocateAndClear(sizeof(RtaProtocolStack));
+ assertNotNull(data->stack_b, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(RtaProtocolStack));
+ data->stack_b->stack_id = 2;
+ data->stack_b->framework = data->framework;
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ // now cleanup everything
+ rtaFramework_Destroy(&data->framework);
+ parcNotifier_Release(&data->commandNotifier);
+ parcRingBuffer1x1_Release(&data->commandRingBuffer);
+
+ parcMemory_Deallocate((void **) &(data->stack_a));
+ parcMemory_Deallocate((void **) &(data->stack_b));
+ parcMemory_Deallocate((void **) &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;
+}
+
+/**
+ * Destroy the table before destroying the connection
+ */
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_AddConnection)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaConnection *conn = createConnection(data->stack_a, 2, 3);
+
+ // This is the part we want to test.
+ RtaConnectionTable *table = rtaConnectionTable_Create(1000, rtaConnection_Destroy);
+ rtaConnectionTable_AddConnection(table, conn);
+
+ assertTrue(table->count_elements == 1, "Incorrect table size, expected %d got %zu", 1, table->count_elements);
+ rtaConnectionTable_Destroy(&table);
+}
+
+
+/**
+ * Create a connection table with just 1 connection and make sure table
+ * does the right thing on overflow
+ */
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_AddConnection_TooMany)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaConnection *conn = createConnection(data->stack_a, 2, 3);
+
+ int res;
+
+ // create the table with size 1
+ RtaConnectionTable *table = rtaConnectionTable_Create(1, rtaConnection_Destroy);
+ res = rtaConnectionTable_AddConnection(table, conn);
+ assertTrue(res == 0, "Got non-zero return %d", res);
+ assertTrue(table->count_elements == 1, "Incorrect table size, expected %d got %zu", 1, table->count_elements);
+
+ // add the second connection, should return failure
+ res = rtaConnectionTable_AddConnection(table, conn);
+ assertTrue(res == -1, "Should have failed, expecting -1, got %d", res);
+
+ rtaConnectionTable_Destroy(&table);
+}
+
+
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_Create_Destroy)
+{
+ size_t beforeBalance = parcMemory_Outstanding();
+ RtaConnectionTable *table = rtaConnectionTable_Create(1000, rtaConnection_Destroy);
+ assertTrue(table->max_elements == 1000, "Initialized with wrong number of elements");
+ rtaConnectionTable_Destroy(&table);
+ size_t afterBalance = parcMemory_Outstanding();
+ assertTrue(beforeBalance == afterBalance, "Memory imbalance after create/destroy");
+}
+
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_GetByApiFd)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaConnection *conn = createConnection(data->stack_a, 2, 3);
+
+ RtaConnectionTable *table = rtaConnectionTable_Create(1000, rtaConnection_Destroy);
+ rtaConnectionTable_AddConnection(table, conn);
+
+ RtaConnection *test;
+ test = rtaConnectionTable_GetByApiFd(table, 2);
+ assertTrue(test == conn, "Got wrong connection, expecting %p got %p", (void *) conn, (void *) test);
+
+ test = rtaConnectionTable_GetByApiFd(table, 3);
+ assertTrue(test == NULL, "Got wrong connection, expecting %p got %p", NULL, (void *) test);
+
+ test = rtaConnectionTable_GetByApiFd(table, 4);
+ assertTrue(test == NULL, "Got wrong connection, expecting %p got %p", NULL, (void *) test);
+
+ rtaConnectionTable_Destroy(&table);
+}
+
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_GetByTransportFd)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaConnection *conn = createConnection(data->stack_a, 2, 3);
+
+ RtaConnectionTable *table = rtaConnectionTable_Create(1000, rtaConnection_Destroy);
+ rtaConnectionTable_AddConnection(table, conn);
+
+ RtaConnection *test;
+ test = rtaConnectionTable_GetByTransportFd(table, 2);
+ assertTrue(test == NULL, "Got wrong connection, expecting %p got %p", NULL, (void *) test);
+
+ test = rtaConnectionTable_GetByTransportFd(table, 3);
+ assertTrue(test == conn, "Got wrong connection, expecting %p got %p", (void *) conn, (void *) test);
+
+ test = rtaConnectionTable_GetByTransportFd(table, 4);
+ assertTrue(test == NULL, "Got wrong connection, expecting %p got %p", NULL, (void *) test);
+
+
+ rtaConnectionTable_Destroy(&table);
+}
+
+/**
+ * We create two connections and make sure that when we remove one the other
+ * is still in the table
+ */
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_Remove)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int res;
+ int a_pair[2];
+ int b_pair[2];
+
+ // we have to use actual socket pairs in this test because Remove will destroy
+ // the last copy of the connection and call close() on the sockets.
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, a_pair);
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, b_pair);
+
+ RtaConnectionTable *table = rtaConnectionTable_Create(1000, rtaConnection_Destroy);
+
+ RtaConnection *conn_a = createConnection(data->stack_a, a_pair[0], a_pair[1]);
+ rtaConnectionTable_AddConnection(table, conn_a);
+
+ RtaConnection *conn_b = createConnection(data->stack_b, b_pair[0], b_pair[1]);
+ rtaConnectionTable_AddConnection(table, conn_b);
+
+ assertTrue(table->count_elements == 2, "Wrong element count");
+
+ res = rtaConnectionTable_Remove(table, conn_b);
+ assertTrue(res == 0, "Got error from rtaConnectionTable_Remove: %d", res);
+ assertTrue(table->count_elements == 1, "Wrong element count");
+
+ RtaConnection *test = rtaConnectionTable_GetByApiFd(table, a_pair[0]);
+ assertNotNull(test, "Could not retrieve connection that was supposed to still be there");
+
+ rtaConnectionTable_Destroy(&table);
+}
+
+/**
+ * Create two connections, they are in different protocol stacks. Remove one by
+ * stack id and make sure the other is still in the table
+ */
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_RemoveByStack)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int res;
+ int a_pair[2];
+ int b_pair[2];
+
+ // we have to use actual socket pairs in this test because Remove will destroy
+ // the last copy of the connection and call close() on the sockets.
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, a_pair);
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, b_pair);
+
+ RtaConnectionTable *table = rtaConnectionTable_Create(1000, rtaConnection_Destroy);
+
+ RtaConnection *conn_a = createConnection(data->stack_a, a_pair[0], a_pair[1]);
+ rtaConnectionTable_AddConnection(table, conn_a);
+
+ RtaConnection *conn_b = createConnection(data->stack_b, b_pair[0], b_pair[1]);
+ rtaConnectionTable_AddConnection(table, conn_b);
+
+ // now remove a connection by stack id
+
+ res = rtaConnectionTable_RemoveByStack(table, data->stack_a->stack_id);
+ assertTrue(res == 0, "Got error from rtaConnectionTable_RemoveByStack: %d", res);
+ assertTrue(table->count_elements == 1, "Wrong element count");
+
+ RtaConnection *test = rtaConnectionTable_GetByApiFd(table, b_pair[0]);
+ assertNotNull(test, "Could not retrieve connection that was supposed to still be there");
+
+ rtaConnectionTable_Destroy(&table);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_ConnectionTable);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework.c
new file mode 100644
index 00000000..715908f3
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework.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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../rta_Framework.c"
+#include <ccnx/transport/transport_rta/commands/rta_Command.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <math.h>
+
+typedef struct test_data {
+ PARCRingBuffer1x1 *commandRingBuffer;
+ PARCNotifier *commandNotifier;
+ RtaFramework *framework;
+} TestData;
+
+
+static TestData *
+_createTestData(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->commandRingBuffer = parcRingBuffer1x1_Create(128, NULL);
+ data->commandNotifier = parcNotifier_Create();
+ data->framework = rtaFramework_Create(data->commandRingBuffer, data->commandNotifier);
+ rtaLogger_SetLogLevel(data->framework->logger, RtaLoggerFacility_Framework, PARCLogLevel_Debug);
+ return data;
+}
+
+static void
+_destroyTestData(TestData *data)
+{
+ parcRingBuffer1x1_Release(&data->commandRingBuffer);
+ parcNotifier_Release(&data->commandNotifier);
+ rtaFramework_Destroy(&data->framework);
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_RUNNER(rta_Framework)
+{
+ 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_Framework)
+{
+ 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_Framework)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ===================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaFramework_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, rtaFramework_GetEventScheduler);
+ LONGBOW_RUN_TEST_CASE(Global, rtaFramework_GetNextConnectionId);
+ LONGBOW_RUN_TEST_CASE(Global, rtaFramework_GetStatus);
+ LONGBOW_RUN_TEST_CASE(Global, rtaFramework_Start_Shutdown);
+ LONGBOW_RUN_TEST_CASE(Global, tick_cb);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _createTestData());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _destroyTestData(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, rtaFramework_Create_Destroy)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertNotNull(data->framework, "rtaFramework_Create returned null");
+ assertTrue(data->framework->commandRingBuffer == data->commandRingBuffer, "framework commandRingBuffer incorrect");
+ assertTrue(data->framework->commandNotifier == data->commandNotifier, "framework commandNotifier incorrect");
+ assertNotNull(data->framework->commandEvent, "framework commandEvent is null");
+}
+
+LONGBOW_TEST_CASE(Global, rtaFramework_GetEventScheduler)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertTrue(rtaFramework_GetEventScheduler(data->framework) == data->framework->base, "getEventScheduler broken");
+}
+
+LONGBOW_TEST_CASE(Global, rtaFramework_GetNextConnectionId)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertTrue(rtaFramework_GetNextConnectionId(data->framework) == 1, "GetNextConnetionId not starting at 1");
+ assertTrue(rtaFramework_GetNextConnectionId(data->framework) == 2, "GetNextConnetionId first increment not 2");
+}
+
+LONGBOW_TEST_CASE(Global, rtaFramework_GetStatus)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertTrue(rtaFramework_GetStatus(data->framework) == FRAMEWORK_INIT, "Wrong initial status");
+}
+
+LONGBOW_TEST_CASE(Global, rtaFramework_Start_Shutdown)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ rtaFramework_Start(data->framework);
+ assertTrue(rtaFramework_WaitForStatus(data->framework, FRAMEWORK_RUNNING) == FRAMEWORK_RUNNING, "Status not RUNNING");
+
+ // blocks until done
+ rtaFramework_Shutdown(data->framework);
+}
+
+LONGBOW_TEST_CASE(Global, tick_cb)
+{
+ ticks tic0, tic1;
+ struct timeval t0, t1;
+ double delta_tic, delta_t, delta_abs;
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ rtaFramework_Start(data->framework);
+ assertTrue(rtaFramework_WaitForStatus(data->framework, FRAMEWORK_RUNNING) == FRAMEWORK_RUNNING, "Status not RUNNING");
+
+ gettimeofday(&t0, NULL);
+ tic0 = data->framework->clock_ticks;
+ sleep(2);
+ gettimeofday(&t1, NULL);
+ tic1 = data->framework->clock_ticks;
+
+ delta_t = (t1.tv_sec + t1.tv_usec * 1E-6) - (t0.tv_sec + t0.tv_usec * 1E-6);
+ delta_tic = ((tic1 - tic0) * FC_USEC_PER_TICK) * 1E-6;
+ delta_abs = fabs(delta_tic - delta_t);
+
+ printf("over 2 seconds, absolute clock error is %.6f seconds\n", delta_abs);
+
+
+ // blocks until done
+ rtaFramework_Shutdown(data->framework);
+}
+
+// ===================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _setLogLevels_All);
+ LONGBOW_RUN_TEST_CASE(Local, _setLogLevels_All_Framework);
+ LONGBOW_RUN_TEST_CASE(Local, _setLogLevels_Framework);
+ LONGBOW_RUN_TEST_CASE(Local, _setLogLevels_ApiConnector);
+ LONGBOW_RUN_TEST_CASE(Local, _setLogLevels_FlowController);
+ LONGBOW_RUN_TEST_CASE(Local, _setLogLevels_Codec);
+ LONGBOW_RUN_TEST_CASE(Local, _setLogLevels_ForwarderConnector);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ longBowTestCase_SetClipBoardData(testCase, _createTestData());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ _destroyTestData(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(Local, _setLogLevels_All)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ setenv("RtaFacility_All", "Warning", 1);
+ _setLogLevels(data->framework);
+
+ for (int i = 0; i < RtaLoggerFacility_END; i++) {
+ bool isLoggable = rtaLogger_IsLoggable(rtaFramework_GetLogger(data->framework), i, PARCLogLevel_Warning);
+ assertTrue(isLoggable, "Facility %s not set to Warning", rtaLogger_FacilityString(i));
+ }
+
+ unsetenv("RtaFacility_All");
+}
+
+LONGBOW_TEST_CASE(Local, _setLogLevels_All_Framework)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ setenv("RtaFacility_All", "Info", 1);
+ setenv("RtaFacility_Framework", "Warning", 1);
+ _setLogLevels(data->framework);
+
+ assertTrue(rtaLogger_IsLoggable(rtaFramework_GetLogger(data->framework), RtaLoggerFacility_ApiConnector, PARCLogLevel_Info), "Api facility not Info");
+ assertTrue(rtaLogger_IsLoggable(rtaFramework_GetLogger(data->framework), RtaLoggerFacility_Framework, PARCLogLevel_Warning), "Framework not Warning");
+
+ unsetenv("RtaFacility_All");
+ unsetenv("RtaFacility_Framework");
+}
+
+LONGBOW_TEST_CASE(Local, _setLogLevels_Framework)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ setenv("RtaFacility_Framework", "Warning", 1);
+ _setLogLevels(data->framework);
+
+ assertFalse(rtaLogger_IsLoggable(rtaFramework_GetLogger(data->framework), RtaLoggerFacility_Framework, PARCLogLevel_Info), "Info should not be loggable");
+ assertTrue(rtaLogger_IsLoggable(rtaFramework_GetLogger(data->framework), RtaLoggerFacility_Framework, PARCLogLevel_Warning), "Warning should be loggable");
+ unsetenv("RtaFacility_Framework");
+}
+
+LONGBOW_TEST_CASE(Local, _setLogLevels_ApiConnector)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ setenv("RtaFacility_Api", "Warning", 1);
+ _setLogLevels(data->framework);
+
+ assertFalse(rtaLogger_IsLoggable(rtaFramework_GetLogger(data->framework), RtaLoggerFacility_ApiConnector, PARCLogLevel_Info), "Info should not be loggable");
+ assertTrue(rtaLogger_IsLoggable(rtaFramework_GetLogger(data->framework), RtaLoggerFacility_ApiConnector, PARCLogLevel_Warning), "Warning should be loggable");
+ unsetenv("RtaFacility_Api");
+}
+
+LONGBOW_TEST_CASE(Local, _setLogLevels_FlowController)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ setenv("RtaFacility_Flowcontrol", "Warning", 1);
+ _setLogLevels(data->framework);
+
+ assertFalse(rtaLogger_IsLoggable(rtaFramework_GetLogger(data->framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Info), "Info should not be loggable");
+ assertTrue(rtaLogger_IsLoggable(rtaFramework_GetLogger(data->framework), RtaLoggerFacility_Flowcontrol, PARCLogLevel_Warning), "Warning should be loggable");
+ unsetenv("RtaFacility_Flowcontrol");
+}
+
+LONGBOW_TEST_CASE(Local, _setLogLevels_Codec)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ setenv("RtaFacility_Codec", "Warning", 1);
+ _setLogLevels(data->framework);
+
+ assertFalse(rtaLogger_IsLoggable(rtaFramework_GetLogger(data->framework), RtaLoggerFacility_Codec, PARCLogLevel_Info), "Info should not be loggable");
+ assertTrue(rtaLogger_IsLoggable(rtaFramework_GetLogger(data->framework), RtaLoggerFacility_Codec, PARCLogLevel_Warning), "Warning should be loggable");
+ unsetenv("RtaFacility_Codec");
+}
+
+LONGBOW_TEST_CASE(Local, _setLogLevels_ForwarderConnector)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ setenv("RtaFacility_Forwarder", "Warning", 1);
+ _setLogLevels(data->framework);
+
+ assertFalse(rtaLogger_IsLoggable(rtaFramework_GetLogger(data->framework), RtaLoggerFacility_ForwarderConnector, PARCLogLevel_Info), "Info should not be loggable");
+ assertTrue(rtaLogger_IsLoggable(rtaFramework_GetLogger(data->framework), RtaLoggerFacility_ForwarderConnector, PARCLogLevel_Warning), "Warning should be loggable");
+ unsetenv("RtaFacility_Forwarder");
+}
+
+// ===================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_Framework);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_Commands.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_Commands.c
new file mode 100644
index 00000000..d19d680b
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_Commands.c
@@ -0,0 +1,449 @@
+/*
+ * 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.
+ */
+
+/**
+ * Creates a bentpipe forwarder and then creates and runs in non-threaded Transport in
+ * the commonSetup() function. The function commonTeardown() undoes all that.
+ *
+ */
+
+#include "../rta_Framework_Commands.c"
+#include <sys/param.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_Security.h>
+
+#include <ccnx/api/control/cpi_ControlMessage.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <ccnx/transport/transport_rta/config/config_All.h>
+#include <ccnx/transport/transport_rta/rta_Transport.h>
+#include <ccnx/transport/common/transport_private.h>
+#include <ccnx/transport/test_tools/traffic_tools.h>
+
+#include <ccnx/transport/test_tools/bent_pipe.h>
+
+// ==============================================
+typedef struct test_data {
+ PARCRingBuffer1x1 *commandRingBuffer;
+ PARCNotifier *commandNotifier;
+ RtaFramework *framework;
+
+ char bentpipe_Directory[MAXPATHLEN];
+ char bentpipe_LocalName[MAXPATHLEN];
+ BentPipeState *bentpipe;
+ char keystoreName[MAXPATHLEN];
+ char keystorePassword[MAXPATHLEN];
+} TestData;
+
+static CCNxTransportConfig *
+_createParams(const char *local_name, const char *keystore_name, const char *keystore_passwd)
+{
+ assertNotNull(local_name, "Got null local name\n");
+ assertNotNull(keystore_name, "Got null keystore name\n");
+ assertNotNull(keystore_passwd, "Got null keystore passwd\n");
+
+ CCNxStackConfig *stackConfig = apiConnector_ProtocolStackConfig(
+ tlvCodec_ProtocolStackConfig(
+ localForwarder_ProtocolStackConfig(
+ protocolStack_ComponentsConfigArgs(ccnxStackConfig_Create(),
+ apiConnector_GetName(),
+ tlvCodec_GetName(),
+ localForwarder_GetName(),
+ NULL))));
+
+ CCNxConnectionConfig *connConfig = apiConnector_ConnectionConfig(
+ localForwarder_ConnectionConfig(ccnxConnectionConfig_Create(), local_name));
+
+ connConfig = tlvCodec_ConnectionConfig(connConfig);
+
+ publicKeySigner_ConnectionConfig(connConfig, keystore_name, keystore_passwd);
+
+ CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig);
+ ccnxStackConfig_Release(&stackConfig);
+ return result;
+}
+
+static void
+_runNonThreaded(TestData *data)
+{
+ rtaFramework_NonThreadedStepTimed(data->framework, &((struct timeval) { 0, 100000 }));
+}
+
+static void
+_stopThreaded(TestData *data)
+{
+ printf("Beginning shutdown pid %d\n", getpid());
+ // blocks until done
+ rtaFramework_Shutdown(data->framework);
+ printf("Finished shutdown pid %d\n", getpid());
+}
+
+static void
+_stopNonThreaded(TestData *data)
+{
+ printf("Beginning shutdown pid %d\n", getpid());
+ rtaFramework_Teardown(data->framework);
+ printf("Finished shutdown pid %d\n", getpid());
+}
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ snprintf(data->bentpipe_Directory, MAXPATHLEN, "/tmp/bentpipe_XXXXXX");
+ char *p = mkdtemp(data->bentpipe_Directory);
+ assertNotNull(p, "Got null from mkdtemp(%s)", data->bentpipe_Directory);
+ snprintf(data->bentpipe_LocalName, MAXPATHLEN, "%s/bentpipe.sock", data->bentpipe_Directory);
+
+ data->bentpipe = bentpipe_Create(data->bentpipe_LocalName);
+ bentpipe_SetChattyOutput(data->bentpipe, false);
+
+ printf("Staring bent pipe pid %d\n", getpid());
+ bentpipe_Start(data->bentpipe);
+ printf("Started bent pipe\n");
+
+ snprintf(data->keystoreName, MAXPATHLEN, "/tmp/keystore_p12_XXXXXX");
+ int fd = mkstemp(data->keystoreName);
+ assertTrue(fd != -1, "Error from mkstemp(%s)", data->keystoreName);
+
+ sprintf(data->keystorePassword, "23439429");
+
+ bool success = parcPkcs12KeyStore_CreateFile(data->keystoreName, data->keystorePassword, "user", 1024, 30);
+ assertTrue(success, "parcPublicKeySignerPkcs12Store_CreateFile() failed.");
+ close(fd);
+
+ data->commandRingBuffer = parcRingBuffer1x1_Create(128, NULL);
+ data->commandNotifier = parcNotifier_Create();
+ data->framework = rtaFramework_Create(data->commandRingBuffer, data->commandNotifier);
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ if (rtaFramework_GetStatus(data->framework) == FRAMEWORK_RUNNING) {
+ _stopThreaded(data);
+ } else {
+ _stopNonThreaded(data);
+ }
+
+ parcRingBuffer1x1_Release(&data->commandRingBuffer);
+ parcNotifier_Release(&data->commandNotifier);
+
+ printf("Destroying framework pid %d\n", getpid());
+ rtaFramework_Destroy(&data->framework);
+
+ bentpipe_Stop(data->bentpipe);
+ bentpipe_Destroy(&data->bentpipe);
+ unlink(data->keystoreName);
+ unlink(data->bentpipe_LocalName);
+ rmdir(data->bentpipe_Directory);
+
+ parcMemory_Deallocate((void **) &data);
+}
+
+
+/**
+ * @function assertConnectionOpen
+ * @abstract Block on reading the 1st message out of the socket. It's the connection ready message.
+ * @discussion
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+static void
+_assertConnectionOpen(int fd)
+{
+ CCNxMetaMessage *firstMessage;
+
+ rtaTransport_Recv(NULL, fd, &firstMessage, CCNxStackTimeout_Never);
+
+ assertTrue(ccnxMetaMessage_IsControl(firstMessage), "not a control message");
+
+ CCNxControl *control = ccnxMetaMessage_GetControl(firstMessage);
+
+ NotifyStatus *status = notifyStatus_ParseJSON(ccnxControl_GetJson(control));
+ ccnxMetaMessage_Release(&firstMessage);
+
+ assertTrue(notifyStatus_IsConnectionOpen(status), "Expected notifyStatus_IsConnectionOpen to be true");
+ notifyStatus_Release(&status);
+}
+
+
+/**
+ * @function openConnection
+ * @abstract Opens a connection and fills in the socket pair
+ * @discussion
+ * uses rtaFramework_ExecuteOpen to directly create, does not go over the command pair
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+static void
+_openConnection(RtaFramework *framework, CCNxTransportConfig *transportConfig, int stack_id, int socketPairOutput[])
+{
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, socketPairOutput);
+
+ struct timeval timeout = { .tv_sec = 10, .tv_usec = 0 };
+
+ setsockopt(socketPairOutput[0], SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
+ setsockopt(socketPairOutput[0], SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+ setsockopt(socketPairOutput[1], SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
+ setsockopt(socketPairOutput[1], SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+
+ RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(stack_id, socketPairOutput[1], socketPairOutput[0],
+ ccnxConnectionConfig_GetJson(ccnxTransportConfig_GetConnectionConfig(transportConfig)));
+
+ _rtaFramework_ExecuteOpenConnection(framework, openConnection);
+ rtaCommandOpenConnection_Release(&openConnection);
+
+ rtaFramework_NonThreadedStepCount(framework, 10);
+ _assertConnectionOpen(socketPairOutput[1]);
+}
+
+static bool
+_readAndCompareName(int fd, CCNxName *truthName)
+{
+ CCNxMetaMessage *test_msg;
+
+ int res = rtaTransport_Recv(NULL, fd, &test_msg, CCNxStackTimeout_Never);
+ assertTrue(res == 0, "Got error receiving on bob's socket: %s (%d)", strerror(errno), errno);
+
+ assertNotNull(test_msg, "Got null message from Bob");
+
+ assertTrue(ccnxMetaMessage_IsInterest(test_msg), "Got wrong type, expected Interest but got other");
+
+ CCNxInterest *interest = ccnxMetaMessage_GetInterest(test_msg);
+
+ assertTrue(ccnxName_Compare(truthName, ccnxInterest_GetName(interest)) == 0, "Names did not compare")
+ {
+ ccnxName_Display(ccnxInterest_GetName(interest), 3);
+ ccnxName_Display(truthName, 3);
+ }
+
+ ccnxMetaMessage_Release(&test_msg);
+
+ return true;
+}
+
+// ==========================
+
+LONGBOW_TEST_RUNNER(rta_Framework_Commands)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(rta_Framework_Commands)
+{
+ printf("\n********\n%s starting\n\n", __func__);
+
+ srandom((int) time(NULL));
+ 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_Framework_Commands)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _rtaFramework_ExecuteCloseConnection);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaFramework_ExecuteCreateStack);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaFramework_ExecuteOpenConnection);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ parcSecurity_Init();
+
+#if __APPLE__
+ pthread_setname_np(longBowTestCase_GetName(testCase));
+#else
+ pthread_setname_np(pthread_self(), longBowTestCase_GetName(testCase));
+#endif
+
+ TestData *data = _commonSetup();
+ _runNonThreaded(data);
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ _commonTeardown(data);
+ parcSecurity_Fini();
+
+ 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, _rtaFramework_ExecuteCloseConnection)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int stack_id = 5;
+
+ CCNxTransportConfig *params = _createParams(data->bentpipe_LocalName, data->keystoreName, data->keystorePassword);
+
+ RtaCommandCreateProtocolStack *createStack =
+ rtaCommandCreateProtocolStack_Create(stack_id, ccnxTransportConfig_GetStackConfig(params));
+
+ _rtaFramework_ExecuteCreateStack(data->framework, createStack);
+ rtaCommandCreateProtocolStack_Release(&createStack);
+
+ // now use three connections, then close 1 and make sure other 2 still ok
+ {
+ int alice_pair[2], bob_pair[2], charlie_pair[2];
+
+ _openConnection(data->framework, params, stack_id, alice_pair);
+ _openConnection(data->framework, params, stack_id, bob_pair);
+ _openConnection(data->framework, params, stack_id, charlie_pair);
+
+ CCNxInterest *firstInterest = trafficTools_CreateInterest();
+
+ // send will consume the message, so copy out the name
+ CCNxName *truth_name = ccnxName_Copy(ccnxInterest_GetName(firstInterest));
+
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(firstInterest);
+ bool success = rtaTransport_Send(NULL, alice_pair[1], message, CCNxStackTimeout_Never);
+ assertTrue(success, "Got error sending on alice's socket: %s (%d)", strerror(errno), errno);
+ ccnxMetaMessage_Release(&message);
+
+ // *** Read bob
+ rtaFramework_NonThreadedStepCount(data->framework, 10);
+ _readAndCompareName(bob_pair[1], truth_name);
+
+ // *** Read Charlie
+ rtaFramework_NonThreadedStepCount(data->framework, 10);
+ _readAndCompareName(charlie_pair[1], truth_name);
+
+ // Close charlie and make sure alice + bob still happy
+ RtaCommandCloseConnection *closeConnection = rtaCommandCloseConnection_Create(charlie_pair[1]);
+ _rtaFramework_ExecuteCloseConnection(data->framework, closeConnection);
+ rtaCommandCloseConnection_Release(&closeConnection);
+ rtaFramework_NonThreadedStepCount(data->framework, 10);
+
+ // send another interest
+ CCNxInterest *secondInterest = trafficTools_CreateInterest();
+ message = ccnxMetaMessage_CreateFromInterest(secondInterest);
+
+ success = rtaTransport_Send(NULL, alice_pair[1], message, CCNxStackTimeout_Never);
+ assertTrue(success, "Got error sending on alice's socket: %s (%d)", strerror(errno), errno);
+ ccnxMetaMessage_Release(&message);
+
+ // make sure bob gets it
+ rtaFramework_NonThreadedStepCount(data->framework, 10);
+ _readAndCompareName(bob_pair[1], truth_name);
+
+ ccnxName_Release(&truth_name);
+ ccnxInterest_Release(&firstInterest);
+ ccnxInterest_Release(&secondInterest);
+ }
+
+ ccnxTransportConfig_Destroy(&params);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaFramework_ExecuteCreateStack)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int stack_id = 4;
+ CCNxTransportConfig *params = _createParams(data->bentpipe_LocalName, data->keystoreName, data->keystorePassword);
+ RtaCommandCreateProtocolStack *createStack =
+ rtaCommandCreateProtocolStack_Create(stack_id, ccnxTransportConfig_GetStackConfig(params));
+
+
+ // this call skirts around threading
+ _rtaFramework_ExecuteCreateStack(data->framework, createStack);
+
+ FrameworkProtocolHolder *holder;
+ holder = rtaFramework_GetProtocolStackByStackId(data->framework, stack_id);
+ assertNotNull(holder, "There is no protocol holder for this stack, not created?");
+
+ ccnxTransportConfig_Destroy(&params);
+ rtaCommandCreateProtocolStack_Release(&createStack);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaFramework_ExecuteOpenConnection)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int stack_id = 4;
+ CCNxTransportConfig *params = _createParams(data->bentpipe_LocalName, data->keystoreName, data->keystorePassword);
+
+ RtaCommandCreateProtocolStack *createStack =
+ rtaCommandCreateProtocolStack_Create(stack_id, ccnxTransportConfig_GetStackConfig(params));
+ _rtaFramework_ExecuteCreateStack(data->framework, createStack);
+ rtaCommandCreateProtocolStack_Release(&createStack);
+
+ // now create two connections and make sure they work
+ {
+ // now create
+ int alice_pair[2], bob_pair[2];
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, alice_pair);
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, bob_pair);
+
+ _openConnection(data->framework, params, stack_id, alice_pair);
+ _openConnection(data->framework, params, stack_id, bob_pair);
+
+ CCNxInterest *interest = trafficTools_CreateInterest();
+
+ //ccnxInterest_Display(interest, 0);
+
+ // send will consume the message, so copy out the name
+ CCNxName *truth_name = ccnxName_Copy(ccnxInterest_GetName(interest));
+
+ //ccnxName_Display(truth_name, 0);
+
+ // now send it down the stack
+ CCNxMetaMessage *message = ccnxMetaMessage_CreateFromInterest(interest);
+ bool success = rtaTransport_Send(NULL, alice_pair[1], message, CCNxStackTimeout_Never);
+ assertTrue(success, "Got error sending on alice's socket: %s (%d)", strerror(errno), errno);
+ ccnxMetaMessage_Release(&message);
+
+ rtaFramework_NonThreadedStepCount(data->framework, 10);
+ _readAndCompareName(bob_pair[1], truth_name);
+
+ ccnxName_Release(&truth_name);
+ ccnxInterest_Release(&interest);
+ }
+
+ ccnxTransportConfig_Destroy(&params);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_Framework_Commands);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_NonThreaded.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_NonThreaded.c
new file mode 100644
index 00000000..fb73e15c
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_NonThreaded.c
@@ -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.
+ */
+
+
+#include "../rta_Framework_NonThreaded.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(rta_Framework_NonThreaded)
+{
+ // 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_Framework_NonThreaded)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_Framework_NonThreaded)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
+
+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_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(rta_Framework_NonThreaded);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_Services.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_Services.c
new file mode 100644
index 00000000..6bb51f0f
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_Services.c
@@ -0,0 +1,84 @@
+/*
+ * 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 "../rta_Framework_Services.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(rta_Framework_Services)
+{
+ // 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_Framework_Services)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_Framework_Services)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
+
+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_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(rta_Framework_Services);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_Threaded.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_Threaded.c
new file mode 100644
index 00000000..74ea2f64
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Framework_Threaded.c
@@ -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.
+ */
+
+
+#include "../rta_Framework_Threaded.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(rta_Framework_Threaded)
+{
+ // 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_Framework_Threaded)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_Framework_Threaded)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
+
+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_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(rta_Framework_Threaded);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Logger.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Logger.c
new file mode 100644
index 00000000..240293fc
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_Logger.c
@@ -0,0 +1,222 @@
+/*
+ * 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 "../rta_Logger.c"
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(rta_Logger)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(rta_Logger)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_Logger)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ==========================================================
+
+/*
+ * _testWritter will vsprintf to this buffer
+ */
+#define _logLength 1024
+static char _lastLogMessage[_logLength];
+
+static int
+_testWriter(const char *message)
+{
+ int written = 0;
+ written = snprintf(_lastLogMessage, _logLength, "%s", message);
+ return written;
+}
+
+static PARCLogReporter *
+_testWriter_Acquire(const PARCLogReporter *reporter)
+{
+ return parcObject_Acquire(reporter);
+}
+
+static void
+_testWriter_Release(PARCLogReporter **reporterPtr)
+{
+ parcObject_Release((void **) reporterPtr);
+}
+
+static void
+_testWriter_Report(PARCLogReporter *reporter, const PARCLogEntry *entry)
+{
+ char *string = parcLogEntry_ToString(entry);
+ _testWriter(string);
+ parcMemory_Deallocate((void **) &string);
+}
+
+static PARCLogReporter *
+_testWriter_Create(void)
+{
+ return parcLogReporter_Create(_testWriter_Acquire, _testWriter_Release, _testWriter_Report, NULL);
+}
+
+// ==========================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaLogger_FacilityString_Found);
+ LONGBOW_RUN_TEST_CASE(Global, rtaLogger_FacilityString_NotFound);
+ LONGBOW_RUN_TEST_CASE(Global, rtaLogger_Create);
+ LONGBOW_RUN_TEST_CASE(Global, rtaLogger_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, rtaLogger_SetLogLevel);
+ LONGBOW_RUN_TEST_CASE(Global, rtaLogger_IsLoggable_True);
+ LONGBOW_RUN_TEST_CASE(Global, rtaLogger_IsLoggable_False);
+ LONGBOW_RUN_TEST_CASE(Global, rtaLogger_Log_IsLoggable);
+ LONGBOW_RUN_TEST_CASE(Global, rtaLogger_Log_IsNotLoggable);
+}
+
+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, rtaLogger_FacilityString_Found)
+{
+ for (RtaLoggerFacility i = 0; i < RtaLoggerFacility_END; i++) {
+ const char *test = rtaLogger_FacilityString(i);
+ assertNotNull(test, "Got null string for facility %d", i);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, rtaLogger_FacilityString_NotFound)
+{
+ const char *test = rtaLogger_FacilityString(1000);
+ assertTrue(strcmp(test, "Unknown") == 0, "Got wrong string for unknown facility");
+}
+
+LONGBOW_TEST_CASE(Global, rtaLogger_Create)
+{
+ PARCLogReporter *reporter = _testWriter_Create();
+ RtaLogger *logger = rtaLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ rtaLogger_Release(&logger);
+}
+
+LONGBOW_TEST_CASE(Global, rtaLogger_Acquire)
+{
+ PARCLogReporter *reporter = _testWriter_Create();
+ RtaLogger *logger = rtaLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ RtaLogger *copy = rtaLogger_Acquire(logger);
+ rtaLogger_Release(&logger);
+ rtaLogger_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, rtaLogger_SetLogLevel)
+{
+ PARCLogReporter *reporter = _testWriter_Create();
+ RtaLogger *logger = rtaLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ rtaLogger_SetLogLevel(logger, RtaLoggerFacility_Framework, PARCLogLevel_Off);
+
+ PARCLogLevel test = parcLog_GetLevel(logger->loggerArray[RtaLoggerFacility_Framework]);
+ assertTrue(test == PARCLogLevel_Off, "wrong log level, expected %d got %d", PARCLogLevel_Off, test);
+ rtaLogger_Release(&logger);
+}
+
+LONGBOW_TEST_CASE(Global, rtaLogger_IsLoggable_True)
+{
+ PARCLogReporter *reporter = _testWriter_Create();
+ RtaLogger *logger = rtaLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ rtaLogger_SetLogLevel(logger, RtaLoggerFacility_Framework, PARCLogLevel_Warning);
+ bool isLoggable = rtaLogger_IsLoggable(logger, RtaLoggerFacility_Framework, PARCLogLevel_Warning);
+ assertTrue(isLoggable, "Did not get true for isLoggable when expecting true");
+ rtaLogger_Release(&logger);
+}
+
+LONGBOW_TEST_CASE(Global, rtaLogger_IsLoggable_False)
+{
+ PARCLogReporter *reporter = _testWriter_Create();
+ RtaLogger *logger = rtaLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ rtaLogger_SetLogLevel(logger, RtaLoggerFacility_Framework, PARCLogLevel_Warning);
+ bool isLoggable = rtaLogger_IsLoggable(logger, RtaLoggerFacility_Framework, PARCLogLevel_Debug);
+ assertFalse(isLoggable, "Logging debug to warning facility should have been false");
+ rtaLogger_Release(&logger);
+}
+
+LONGBOW_TEST_CASE(Global, rtaLogger_Log_IsLoggable)
+{
+ PARCLogReporter *reporter = _testWriter_Create();
+ RtaLogger *logger = rtaLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ rtaLogger_SetLogLevel(logger, RtaLoggerFacility_Framework, PARCLogLevel_Warning);
+ memset(_lastLogMessage, 0, _logLength);
+
+ rtaLogger_Log(logger, RtaLoggerFacility_Framework, PARCLogLevel_Warning, __func__, "hello");
+ assertTrue(strlen(_lastLogMessage) > 0, "Did not write to log message");
+ rtaLogger_Release(&logger);
+}
+
+LONGBOW_TEST_CASE(Global, rtaLogger_Log_IsNotLoggable)
+{
+ PARCLogReporter *reporter = _testWriter_Create();
+ RtaLogger *logger = rtaLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ rtaLogger_SetLogLevel(logger, RtaLoggerFacility_Framework, PARCLogLevel_Warning);
+ memset(_lastLogMessage, 0, _logLength);
+
+ rtaLogger_Log(logger, RtaLoggerFacility_Framework, PARCLogLevel_Debug, __func__, "hello");
+ assertTrue(strlen(_lastLogMessage) == 0, "Should not have written to log message");
+ rtaLogger_Release(&logger);
+}
+
+
+// ==========================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_Logger);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ProtocolStack.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ProtocolStack.c
new file mode 100644
index 00000000..c14d799a
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ProtocolStack.c
@@ -0,0 +1,81 @@
+/*
+ * 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 <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(rta_ProtocolStack)
+{
+ 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_ProtocolStack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_ProtocolStack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
+
+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_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(rta_ProtocolStack);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_WebService.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_WebService.c
new file mode 100644
index 00000000..4b2fb015
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_WebService.c
@@ -0,0 +1,301 @@
+/*
+ * 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 "../rta_WebService.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <signal.h>
+#include <pthread.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+LONGBOW_TEST_RUNNER(rta_WebService)
+{
+ // 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_WebService)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_WebService)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaWebService_Create_Destroy);
+}
+
+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;
+}
+
+struct sigaction save_sigchld;
+struct sigaction save_sigpipe;
+
+static void
+blockSigChild()
+{
+ struct sigaction ignore_action;
+ ignore_action.sa_handler = SIG_IGN;
+ sigemptyset(&ignore_action.sa_mask);
+ ignore_action.sa_flags = 0;
+
+ sigaction(SIGCHLD, NULL, &save_sigchld);
+ sigaction(SIGPIPE, NULL, &save_sigpipe);
+
+ sigaction(SIGCHLD, &ignore_action, NULL);
+ sigaction(SIGPIPE, &ignore_action, NULL);
+}
+
+static void
+unblockSigChild()
+{
+ sigaction(SIGCHLD, &save_sigchld, NULL);
+ sigaction(SIGPIPE, &save_sigpipe, NULL);
+}
+
+LONGBOW_TEST_CASE(Global, rtaWebService_Create_Destroy)
+{
+ int fds[2];
+ int failure = socketpair(AF_LOCAL, SOCK_STREAM, 0, fds);
+ assertFalse(failure, "error on socketpair: (%d) %s", errno, strerror(errno));
+
+ RtaFramework *framework = rtaFramework_Create(fds[1]);
+
+ // we should be runing on port 9090, so the string popen() gets
+ // will look like this:
+ // tcp4 0 0 127.0.0.1.9090 *.* LISTEN
+
+ blockSigChild();
+ FILE *fp = popen("netstat -an -p tcp", "r");
+ assertNotNull(fp, "Got null opening netstat for reading");
+
+ char str[1035];
+ bool found = false;
+ while (fgets(str, sizeof(str) - 1, fp) != NULL) {
+ if (strstr(str, "127.0.0.1.9090") != NULL) {
+ found = true;
+ break;
+ }
+
+ if (strstr(str, "127.0.0.1:9090") != NULL) {
+ found = true;
+ break;
+ }
+ }
+
+ pclose(fp);
+
+ rtaFramework_Destroy(&framework);
+
+ close(fds[0]);
+ close(fds[1]);
+ unblockSigChild();
+
+ assertTrue(found, "Did not find 127.0.0.1.9090 in netstat output");
+}
+
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, rtaWebService_ProcessHelloRequest);
+ LONGBOW_RUN_TEST_CASE(Local, rtaWebService_ProcessRequest);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ 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, rtaWebService_ProcessHelloRequest)
+{
+#ifndef __APPLE__
+ testSkip("Test broken on non-darwin");
+#endif
+
+ blockSigChild();
+ int fds[2];
+ int failure = socketpair(AF_LOCAL, SOCK_STREAM, 0, fds);
+ assertFalse(failure, "error on socketpair: (%d) %s", errno, strerror(errno));
+
+ RtaFramework *framework = rtaFramework_Create(fds[0]);
+ rtaFramework_Start(framework);
+ rtaFramework_WaitForStatus(framework, FRAMEWORK_RUNNING);
+
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+
+ struct sockaddr_in sin;
+ sin.sin_addr.s_addr = inet_addr("127.0.0.1");
+ sin.sin_port = htons(9090);
+
+ failure = connect(fd, (struct sockaddr *) &sin, sizeof(sin));
+ assertFalse(failure, "error on connect: (%d) %s", errno, strerror(errno));
+
+ char request[] = "GET /hello HTTP/1.1\r\n\r\n";
+ ssize_t write_length = write(fd, request, sizeof(request));
+ assertFalse(write_length < 0, "Error writing: (%d) %s", errno, strerror(errno));
+
+
+ struct truth_s {
+ char *line;
+ } truth[] = {
+ { .line = "HTTP/1.1 200 OK\r\n" },
+ { .line = "" }, // do not care line for Date
+ { .line = "Content-Length: 18\r\n" },
+ { .line = "Content-Type: text/html; charset=ISO-8859-1\r\n" },
+ { .line = "\r\n" },
+ { .line = "Requested: /hello\n" },
+ { .line = NULL }
+ };
+
+ // read response line by line
+ FILE *fh = fdopen(fd, "r");
+ int count = 0;
+ while (!feof(fh) && truth[count].line != NULL) {
+ assertNotNull(truth[count].line, "read too many lines: %d", count);
+
+ char response[16384];
+ fgets(response, sizeof(response), fh);
+ if (truth[count].line[0] != '\0') {
+ bool result = strcmp(truth[count].line, response) == 0;
+
+ if (!result) {
+ // we need to cleanup the server or the next test will fail
+ rtaFramework_Shutdown(framework, fds[1]);
+ rtaFramework_Destroy(&framework);
+ close(fds[0]);
+ close(fds[1]);
+ unblockSigChild();
+ assertTrue(result, "mismatched lines, expected '%s' got '%s'", truth[count].line, response);
+ }
+ }
+ count++;
+ }
+ fclose(fh);
+
+ rtaFramework_Shutdown(framework, fds[1]);
+ rtaFramework_Destroy(&framework);
+ close(fds[0]);
+ close(fds[1]);
+
+ unblockSigChild();
+}
+
+LONGBOW_TEST_CASE(Local, rtaWebService_ProcessRequest)
+{
+#ifndef __APPLE__
+ testSkip("Test broken on non-darwin");
+#endif
+
+ blockSigChild();
+ int fds[2];
+ int failure = socketpair(AF_LOCAL, SOCK_STREAM, 0, fds);
+ assertFalse(failure, "error on socketpair: (%d) %s", errno, strerror(errno));
+
+ RtaFramework *framework = rtaFramework_Create(fds[0]);
+ rtaFramework_Start(framework);
+ rtaFramework_WaitForStatus(framework, FRAMEWORK_RUNNING);
+
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+
+ struct sockaddr_in sin;
+ sin.sin_addr.s_addr = inet_addr("127.0.0.1");
+ sin.sin_port = htons(9090);
+
+ failure = connect(fd, (struct sockaddr *) &sin, sizeof(sin));
+ assertFalse(failure, "error on connect: (%d) %s", errno, strerror(errno));
+
+ char request[] = "GET /foo HTTP/1.1\r\n\r\n";
+ write(fd, request, sizeof(request));
+
+ struct truth_s {
+ char *line;
+ } truth[] = {
+ { .line = "HTTP/1.1 404 Document was not found\r\n" },
+ { .line = "Content-Type: text/html\r\n" },
+ { .line = "Connection: close\r\n" },
+ { .line = "" }, // do not care line for Date
+ { .line = "Content-Length: 116\r\n" },
+ { .line = "\r\n" },
+ { .line = "<HTML><HEAD>\n" },
+ { .line = "<TITLE>404 Document was not found</TITLE>\n" },
+ { .line = "</HEAD><BODY>\n" },
+ { .line = "<H1>Document was not found</H1>\n" },
+ { .line = "</BODY></HTML>\n" },
+ { .line = NULL }
+ };
+
+ // read response line by line
+ FILE *fh = fdopen(fd, "r");
+ int count = 0;
+ while (!feof(fh) && truth[count].line != NULL) {
+ assertNotNull(truth[count].line, "read too many lines: %d", count);
+
+ char response[16384];
+ fgets(response, sizeof(response), fh);
+ if (truth[count].line[0] != '\0') {
+ assertTrue(strcmp(truth[count].line, response) == 0, "mismatched lines, expected '%s' got '%s'", truth[count].line, response);
+ }
+ count++;
+ }
+ fclose(fh);
+
+ rtaFramework_Shutdown(framework, fds[1]);
+ rtaFramework_Destroy(&framework);
+ close(fds[0]);
+ close(fds[1]);
+ unblockSigChild();
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_WebService);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/rta_Transport.c b/libccnx-transport-rta/ccnx/transport/transport_rta/rta_Transport.c
new file mode 100644
index 00000000..9724322c
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/rta_Transport.c
@@ -0,0 +1,543 @@
+/*
+ * 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 the API-thread's interface to the RTA framework. It is thread-safe
+ * and executes in the API's thread.
+ *
+ * The only data maintained here is a mapping from the SYSTEM parameters hash
+ * to the stack_id.
+ *
+ * Communication with the Framework is done over a socket pair.
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+
+#include <parc/algol/parc_Memory.h>
+//#include <parc/logging/parc_Log.h>
+//#include <parc/logging/parc_LogReporterTextStdout.h>
+#include <parc/concurrent/parc_RingBuffer_1x1.h>
+#include <parc/concurrent/parc_Notifier.h>
+#include <parc/algol/parc_Deque.h>
+#include <parc/concurrent/parc_Synchronizer.h>
+
+#include <ccnx/transport/transport_rta/rta_Transport.h>
+#include <ccnx/transport/common/transport_private.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework.h>
+#include <ccnx/transport/transport_rta/core/rta_ProtocolStack.h>
+#include <ccnx/transport/transport_rta/commands/rta_Command.h>
+#include <ccnx/transport/transport_rta/core/components.h>
+#include <ccnx/transport/transport_rta/core/rta_ConnectionTable.h>
+
+// These are some internal diagnostic counters used in the debugger
+// for when things are going really bad. They are incremented on each
+// call to read or write.
+unsigned rta_transport_reads = 0;
+unsigned rta_transport_read_spin = 0;
+unsigned rta_transport_writes = 0;
+
+// ===================================================
+// The external interface
+
+const struct transport_operations rta_ops = {
+ .Create = (void * (*)(void))rtaTransport_Create,
+ .Open = (int (*)(void *, CCNxTransportConfig *))rtaTransport_Open,
+ .Send = (int (*)(void *, int, CCNxMetaMessage *, const struct timeval *restrict timeout))rtaTransport_Send,
+ .Recv = (TransportIOStatus (*)(void *, int, CCNxMetaMessage **, const struct timeval *restrict timeout))rtaTransport_Recv,
+ .Close = (int (*)(void *, int))rtaTransport_Close,
+ .Destroy = (int (*)(void **))rtaTransport_Destroy,
+ .PassCommand = (int (*)(void *, void *))rtaTransport_PassCommand
+};
+
+/**
+ * @typedef _StackEntry
+ * @abstract Tracks the JSON descriptions of protocol stacks
+ * @constant hash The hash of the JSON description
+ * @constant stack_id the id of the stack associated with that hash
+ * @constant list The linked-list member
+ * @discussion <#Discussion#>
+ */
+typedef struct json_hash_table {
+ PARCHashCode hash;
+ int stack_id;
+} _StackEntry;
+
+typedef struct socket_pair {
+ int up;
+ int down;
+} _RTASocketPair;
+
+struct rta_transport {
+ RtaFramework *framework; /**< The RTA Framework holding the transport */
+
+ PARCRingBuffer1x1 *commandRingBuffer; /**< Written from Transport down to Framework */
+
+ PARCNotifier *commandNotifier; /**< Shared with the Framework to indicates writes to the ring buffer */
+
+ unsigned int nextStackId;
+
+ PARCDeque *list;
+};
+
+static _StackEntry *
+_rtaTransport_GetStack(const RTATransport *transport, PARCHashCode hash)
+{
+ _StackEntry *result = NULL;
+
+ PARCIterator *iterator = parcDeque_Iterator(transport->list);
+ while (parcIterator_HasNext(iterator)) {
+ _StackEntry *entry = parcIterator_Next(iterator);
+ if (entry->hash == hash) {
+ result = entry;
+ break;
+ }
+ }
+ parcIterator_Release(&iterator);
+
+ return result;
+}
+
+static _StackEntry *
+_rtaTransport_AddStack(RTATransport *transport, CCNxStackConfig *stackConfig)
+{
+ PARCHashCode hash = ccnxStackConfig_HashCode(stackConfig);
+
+ _StackEntry *entry = parcMemory_AllocateAndClear(sizeof(_StackEntry));
+ assertNotNull(entry, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(_StackEntry));
+ entry->hash = hash;
+ entry->stack_id = transport->nextStackId++;
+
+ parcDeque_Append(transport->list, entry);
+
+ return entry;
+}
+
+static void
+_rtaTransport_CommandBufferEntryDestroyer(void **entryPtr)
+{
+}
+
+static bool
+_rtaTransport_SendCommandToFramework(RTATransport *transport, const RtaCommand *command)
+{
+ bool success = rtaCommand_Write(command, transport->commandRingBuffer);
+ if (success) {
+ parcNotifier_Notify(transport->commandNotifier);
+ return true;
+ }
+ return false;
+}
+
+RTATransport *
+rtaTransport_Create(void)
+{
+ RTATransport *transport = parcMemory_AllocateAndClear(sizeof(RTATransport));
+
+ if (transport != NULL) {
+ transport->nextStackId = 1;
+
+ transport->commandRingBuffer = parcRingBuffer1x1_Create(128, _rtaTransport_CommandBufferEntryDestroyer);
+ transport->commandNotifier = parcNotifier_Create();
+
+ transport->framework = rtaFramework_Create(transport->commandRingBuffer, transport->commandNotifier);
+ assertNotNull(transport->framework, "rtaFramework_Create returned null");
+
+ rtaFramework_Start(transport->framework);
+ transport->list = parcDeque_Create();
+ }
+
+ return transport;
+}
+
+int
+rtaTransport_Destroy(RTATransport **ctxPtr)
+{
+ assertNotNull(ctxPtr, "called with null context pointer");
+ RTATransport *transport = *ctxPtr;
+
+ // %%%%% LOCK (notice this lock never gets unlocked, it just gets deleted)
+ parcDeque_Lock(transport->list);
+
+ // This blocks until shutdown (state FRAMEWORK_SHUTDOWN)
+ rtaFramework_Shutdown(transport->framework);
+
+ // This will close and drain all the API fds
+ rtaFramework_Destroy(&transport->framework);
+
+ parcNotifier_Release(&transport->commandNotifier);
+ parcRingBuffer1x1_Release(&transport->commandRingBuffer);
+
+ // Destroy the state we have stored locally to map JSON protocol stack descriptions
+ // to stack_id identifiers.
+
+ for (size_t index = 0; index < parcDeque_Size(transport->list); index++) {
+ _StackEntry *entry = parcDeque_GetAtIndex(transport->list, index);
+ parcMemory_Deallocate((void **) &entry);
+ }
+
+ parcDeque_Release(&transport->list);
+
+ parcMemory_Deallocate((void **) ctxPtr);
+
+// printf("rta_transport writes=%9u reads=%9u spins=%9u\n", rta_transport_writes, rta_transport_reads, rta_transport_read_spin);
+ return 0;
+}
+
+static _RTASocketPair
+_rtaTransport_CreateSocketPair(const RTATransport *transport, int bufferSize)
+{
+ int fds[2];
+
+ bool success = (socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) == 0);
+ assertTrue(success, "socketpair(PF_LOCAL, SOCK_STREAM, ...) failed.");
+
+ _RTASocketPair result = { .up = fds[0], .down = fds[1] };
+
+ // Set buffer size
+ int sendbuff = bufferSize;
+
+ success = (setsockopt(result.up, SOL_SOCKET, SO_RCVBUF, &sendbuff, sizeof(sendbuff)) == 0);
+ assertTrue(success, "Expected success for setsockopt SO_RCVBUF");
+
+ success = (setsockopt(result.down, SOL_SOCKET, SO_RCVBUF, &sendbuff, sizeof(sendbuff)) == 0);
+ assertTrue(success, "Expected success for setsockopt SO_RCVBUF");
+
+ return result;
+}
+
+/**
+ * Returns the protocol stack entry from our table
+ *
+ * Determine if we already have a protocol stack with the same structure as the user asks for.
+ * If so, return that entry, otherwise return NULL
+ *
+ * @param [in] transport The RTA transport
+ * @param [in] transportConfig the configuration the user is asking for
+ *
+ * @return non-NULL The existing protocol stack holder
+ * @return NULL Configuration does not exist
+ */
+static _StackEntry *
+_rtaTransport_GetProtocolStackEntry(RTATransport *transport, CCNxTransportConfig *transportConfig)
+{
+ PARCHashCode hash = ccnxStackConfig_HashCode(ccnxTransportConfig_GetStackConfig(transportConfig));
+
+ _StackEntry *stack = _rtaTransport_GetStack(transport, hash);
+ return stack;
+}
+
+/**
+ * Add a protocol stack
+ *
+ * Adds an entry to our local table of Config -> stack_id mapping and sends a
+ * command over the command socket to create the protocol stack.
+ *
+ * @param [in] transport The RTA transport
+ * @param [in] transportConfig the user specified configuration
+ *
+ * @return non-NULL The holder of the protocol stack mapping
+ * @return NULL An error
+ */
+static _StackEntry *
+_rtaTransport_AddProtocolStackEntry(RTATransport *transport, const CCNxTransportConfig *transportConfig)
+{
+ CCNxStackConfig *stackConfig = ccnxTransportConfig_GetStackConfig(transportConfig);
+
+ _StackEntry *stack = _rtaTransport_AddStack(transport, stackConfig);
+
+ RtaCommandCreateProtocolStack *createStack = rtaCommandCreateProtocolStack_Create(stack->stack_id, stackConfig);
+
+ // request for a new protocol stack, create it
+
+ // now actually create the protocol stack by writing a command over the thread boundary
+ // using the Command socket.
+ RtaCommand *command = rtaCommand_CreateCreateProtocolStack(createStack);
+ _rtaTransport_SendCommandToFramework(transport, command);
+
+ rtaCommand_Release(&command);
+ rtaCommandCreateProtocolStack_Release(&createStack);
+
+ return stack;
+}
+
+/**
+ * Create a new connection
+ *
+ * We have resolved that a matching protocol stack exists, and is represented by
+ * protocolStackHashEntry. We now want to send a command over the command socket to
+ * create a connection in that stack.
+ *
+ * @param [in] transport The RTA transport
+ * @param [in] transportConfig The user requested configuration
+ * @param [in] protocolStackHashEntry The protocol stack holder
+ * @param [in] pair A _RTASocketPair representing the queue of data between the API and the transport stack.
+ */
+static void
+_rtaTransport_CreateConnection(RTATransport *transport, CCNxTransportConfig *transportConfig, _StackEntry *stack, _RTASocketPair pair)
+{
+ RtaCommandOpenConnection *openConnection =
+ rtaCommandOpenConnection_Create(stack->stack_id,
+ pair.up,
+ pair.down,
+ ccnxConnectionConfig_GetJson(ccnxTransportConfig_GetConnectionConfig(transportConfig)));
+
+ RtaCommand *command = rtaCommand_CreateOpenConnection(openConnection);
+ _rtaTransport_SendCommandToFramework(transport, command);
+
+ rtaCommand_Release(&command);
+ rtaCommandOpenConnection_Release(&openConnection);
+}
+
+int
+rtaTransport_Open(RTATransport *transport, CCNxTransportConfig *transportConfig)
+{
+ ccnxTransportConfig_OptionalAssertValid(transportConfig);
+
+ assertNotNull(transport, "Parameter transport must be a valid RTATransport");
+
+ _RTASocketPair pair = _rtaTransport_CreateSocketPair(transport, sizeof(void *) * 128);
+
+ parcDeque_Lock(transport->list);
+ {
+ _StackEntry *stack = _rtaTransport_GetProtocolStackEntry(transport, transportConfig);
+ if (stack == NULL) {
+ stack = _rtaTransport_AddProtocolStackEntry(transport, transportConfig);
+ }
+ assertNotNull(stack, "Got NULL hash entry from _rtaTransport_AddProtocolStackEntry");
+
+ _rtaTransport_CreateConnection(transport, transportConfig, stack, pair);
+ }
+ parcDeque_Unlock(transport->list);
+
+ return pair.up;
+}
+
+/**
+ * timeout is either NULL or a pointer to an unsigned integer containing the number of microseconds to wait for input.
+ *
+ * @return <0 An error occured
+ * @return 0 A timeout occurred waiting for the filedescriptor to have some output space available.
+ * @return >0 The filedescriptor has some output space available.
+ */
+static int
+_rtaTransport_SendSelect(const int fd, const uint64_t *microSeconds)
+{
+ struct timeval timeval;
+ fd_set writeSet;
+
+ FD_ZERO(&writeSet); // clear the set
+ FD_SET(fd, &writeSet); // add our file descriptor to the set
+
+ struct timeval *timeout = NULL;
+
+ if (microSeconds != NULL) {
+ timeval.tv_sec = (int) (*microSeconds / 1000000);
+ timeval.tv_usec = (int) (*microSeconds % 1000000);
+ timeout = &timeval;
+ }
+
+ int selectResult = select(fd + 1, NULL, &writeSet, NULL, timeout);
+
+ return selectResult;
+}
+
+bool
+rtaTransport_Send(RTATransport *transport, int queueId, const CCNxMetaMessage *message, const uint64_t *microSeconds)
+{
+ // Acquire a reference to the incoming CCNxMetaMessage so if the caller releases it immediately,
+ // a reference still exists for the transport. This reference is released once the
+ // message is processed lower in the stack.
+ CCNxMetaMessage *metaMessage = ccnxMetaMessage_Acquire(message);
+
+ rta_transport_writes++;
+
+ int selectResult = _rtaTransport_SendSelect(queueId, microSeconds);
+ if (selectResult < 0) {
+ // We couldn't send it. Release our reference and return signaling failure.
+ ccnxMetaMessage_Release(&metaMessage);
+ return false;
+ } else if (selectResult == 0) {
+ errno = EWOULDBLOCK;
+ ccnxMetaMessage_Release(&metaMessage);
+ return false;
+ } else if (selectResult > 0) {
+ ssize_t count = write(queueId, &metaMessage, sizeof(&metaMessage));
+ if (count == sizeof(&metaMessage)) {
+ return true;
+ }
+ }
+
+ // We couldn't send it. Release our reference and return signaling failure.
+ ccnxMetaMessage_Release(&metaMessage);
+
+ return false;
+}
+
+//#if 1
+/**
+ * @return -1 An error occured
+ * @return 0 A timeout occurred waiting for the filedescriptor to have some input available.
+ * @return >0 The filedescriptor has some input ready.
+ */
+static int
+_rtaTransport_ReceiveSelect(const int fd, const uint64_t *microSeconds)
+{
+ fd_set readSet;
+
+ FD_ZERO(&readSet); // clear the set
+ FD_SET(fd, &readSet); // add our file descriptor to the set
+
+ struct timeval *timeout = NULL;
+ struct timeval timeval;
+
+ if (microSeconds != NULL) {
+ timeval.tv_sec = (int) (*microSeconds / 1000000);
+ timeval.tv_usec = (int) (*microSeconds % 1000000);
+ timeout = &timeval;
+ }
+ int selectResult = select(fd + 1, &readSet, NULL, NULL, (struct timeval *) timeout);
+
+ return selectResult;
+}
+
+TransportIOStatus
+rtaTransport_Recv(RTATransport *transport, const int queueId, CCNxMetaMessage **msgPtr, const uint64_t *microSeconds)
+{
+ // The effect here is to transfer the reference to the CCNxMetaMessage to the application-side thread.
+ // Thus, no acquire or release here as the caller is responsible for releasing the CCNxMetaMessage
+
+ int selectResult = _rtaTransport_ReceiveSelect(queueId, microSeconds);
+
+ if (selectResult == -1) {
+ // errno should have been set by the select(2) system call.
+ return TransportIOStatus_Error;
+ } else if (selectResult == 0) {
+ // errno = EWOULDBLOCK;
+ errno = ENOMSG;
+ return TransportIOStatus_Timeout;
+ }
+
+ size_t remaining = sizeof(&*msgPtr);
+ uint8_t *bytes = (uint8_t *) msgPtr;
+
+ do {
+ ssize_t nread = read(queueId, &bytes[sizeof(&*msgPtr) - remaining], remaining);
+ if (nread == -1 && errno != EINTR) {
+ return TransportIOStatus_Error;
+ }
+ if (nread == 0) {
+ rta_transport_read_spin++;
+ }
+ remaining -= nread;
+ } while (remaining > 0);
+
+ rta_transport_reads++;
+
+ errno = 0;
+ return TransportIOStatus_Success;
+}
+//#else
+///**
+// * @return -1 An error occured
+// * @return 0 A timeout occurred waiting for the filedescriptor to have some input available.
+// * @return >0 The filedescriptor has some input ready.
+// */
+//static int
+//_rtaTransport_Select(const int fd, const struct timeval *restrict timeout)
+//{
+// fd_set readSet;
+//
+// FD_ZERO(&readSet); // clear the set
+// FD_SET(fd, &readSet); // add our file descriptor to the set
+//
+// int selectResult = select(fd + 1, &readSet, NULL, NULL, (struct timeval *) timeout);
+//
+// return selectResult;
+//}
+//
+//TransportIOStatus
+//rtaTransport_Recv(RTATransport *transport, const int queueId, CCNxMetaMessage **msgPtr, const struct timeval *restrict timeout)
+//{
+// // The effect here is to transfer the reference to the CCNxMetaMessage to the application-side thread.
+// // Thus, no acquire or release here as the caller is responsible for releasing the CCNxMetaMessage
+//
+// int selectResult = _rtaTransport_Select(queueId, timeout);
+//
+// if (selectResult == -1) {
+// // errno should have been set by the select(2) system call.
+// return TransportIOStatus_Error;
+// } else if (selectResult == 0) {
+//// errno = EWOULDBLOCK;
+// errno = ENOMSG;
+// return TransportIOStatus_Timeout;
+// }
+//
+// size_t remaining = sizeof(&*msgPtr);
+// uint8_t *bytes = (uint8_t *) msgPtr;
+//
+// do {
+// ssize_t nread = read(queueId, &bytes[sizeof(&*msgPtr) - remaining], remaining);
+// if (nread == -1 && errno != EINTR) {
+// return TransportIOStatus_Error;
+// }
+// if (nread == 0) {
+// rta_transport_read_spin++;
+// }
+// remaining -= nread;
+// } while (remaining > 0);
+//
+// rta_transport_reads++;
+//
+// errno = 0;
+// return TransportIOStatus_Success;
+//}
+//#endif
+
+int
+rtaTransport_Close(RTATransport *transport, int api_fd)
+{
+ RtaCommandCloseConnection *commandClose = rtaCommandCloseConnection_Create(api_fd);
+ RtaCommand *command = rtaCommand_CreateCloseConnection(commandClose);
+ rtaCommandCloseConnection_Release(&commandClose);
+
+ _rtaTransport_SendCommandToFramework(transport, command);
+
+ rtaCommand_Release(&command);
+
+ return 0;
+}
+
+int
+rtaTransport_PassCommand(RTATransport *transport, const RtaCommand *rtacommand)
+{
+ _rtaTransport_SendCommandToFramework(transport, rtacommand);
+
+ return 0;
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/rta_Transport.h b/libccnx-transport-rta/ccnx/transport/transport_rta/rta_Transport.h
new file mode 100644
index 00000000..44ac7cb0
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/rta_Transport.h
@@ -0,0 +1,101 @@
+/*
+ * 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 <stdint.h>
+#include <ccnx/transport/common/transport.h>
+
+/**
+ * rtaTransport executes in the API's thread. It glues the bottom half of
+ * the Transport API to the RTA transport. It owns and manages a worker thread
+ * in which the event schduler executes.
+ *
+ * rtaTransport is thread safe. You may have multiple threads using the same
+ * transport context.
+ *
+ * Inside the worker thread, the event scheduler executes without locks. Therefore we need
+ * to message pass to it and have it execute our commands in a managed callback.
+ * This is done by passing commands (JSON) over a socket pair.
+ *
+ * Inside the worker thread, rta_Framework provides service utilities to components
+ * and connectors. It also manages the command socket.
+ *
+ * When an API calls <code>int rtaTransport_Open(CCNxJSON *params)</code>, rtaTransport
+ * will create a socket pair and give one back to the api (api_fd) and send one to
+ * rtaFramework (transport_fd).
+ *
+ * The socket commands are (in JSON):
+ *
+ * PARAMS := existing SYSTEM and USER JSON objects, i.e.:
+ * { "SYSTEM" : {...}, "USER" : {...} }
+ *
+ * { "RTA" : { "CREATE STACK" : stack_id, PARAMS }
+ * { "RTA" : { "OPEN" : [stack_id, api_fd, transport_fd], PARAMS } }
+ * { "RTA" : { "CLOSE": transport_fd } }
+ * { "RTA" : { "DESTROY STACK": stack_id } }
+ * { "RTA" : { "SHUTDOWN" }
+ *
+ * See rta_Commands.h for an implementation of this.
+ */
+#ifndef Libccnx_rta_Transport_h
+#define Libccnx_rta_Transport_h
+
+#include <ccnx/transport/common/transport.h>
+#include <ccnx/transport/transport_rta/commands/rta_Command.h>
+
+/**
+ * Transport Ready To Assemble context
+ *
+ */
+struct rta_transport;
+typedef struct rta_transport RTATransport;
+
+/**
+ * Structure of function points to operate on Transport RTA
+ *
+ */
+extern const struct transport_operations rta_ops;
+
+/**
+ * Create the transport. No locks here, as rtaFramework_Create and rtaFramework_Start
+ * are thread-safe functions and we dont maintain any data.
+ *
+ */
+RTATransport *rtaTransport_Create(void);
+
+int rtaTransport_Destroy(RTATransport **ctxPtr);
+
+int rtaTransport_Open(RTATransport *ctx, CCNxTransportConfig *transportConfig);
+
+/**
+ * Send a CCNxMetaMessage on the outbound direction of the stack.
+ *
+ * @param [in] transport A pointer to a valid RTATransport instance.
+ * @param [in] queueId The identifier of the asynchronous queue between the top and bottom halves of the stack.
+ * @param [in] message A pointer to a valid CCNxMetaMessage instance.
+ *
+ * @return true The send was successful
+ * @return false The send was not successful
+ */
+//bool rtaTransport_Send(RTATransport *transport, int queueId, const CCNxMetaMessage *message, const struct timeval *restrict timeout);
+bool rtaTransport_Send(RTATransport *transport, int queueId, const CCNxMetaMessage *message, const uint64_t *microSeconds);
+
+TransportIOStatus rtaTransport_Recv(RTATransport *transport, const int queueId, CCNxMetaMessage **msgPtr, const uint64_t *microSeconds);
+
+int rtaTransport_Close(RTATransport *transport, int desc);
+
+int rtaTransport_PassCommand(RTATransport *transport, const RtaCommand *rtacommand);
+
+#endif // Libccnx_rta_Transport_h
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/test/.gitignore b/libccnx-transport-rta/ccnx/transport/transport_rta/test/.gitignore
new file mode 100644
index 00000000..90005943
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/test/.gitignore
@@ -0,0 +1,19 @@
+rtatest
+test_bent_pipe
+test_component_Ccnd_Registrar
+test_component_Codec_Ccnb
+test_component_Codec_Tlv_Hmac
+test_connector_Api
+test_connector_Forwarder_Ccnd
+test_connector_Forwarder_Flan
+test_connector_Forwarder_Local
+test_fc_vegas
+test_multi_connections
+test_rta_Commands
+test_rta_ConnectionTable
+test_rta_Framework
+test_rta_Framework_Commands
+test_rta_WebService
+test_system_passthrough
+test_connector_Forwarder_Metis
+
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/test/CMakeLists.txt b/libccnx-transport-rta/ccnx/transport/transport_rta/test/CMakeLists.txt
new file mode 100644
index 00000000..c52b0166
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/test/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_multi_connections
+ test_rta_Transport
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/test/README b/libccnx-transport-rta/ccnx/transport/transport_rta/test/README
new file mode 100644
index 00000000..8a325828
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/test/README
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ *
+ */
+
+These are system tests, not specific to any one component or connector
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_multi_connections.c b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_multi_connections.c
new file mode 100644
index 00000000..8f0051a0
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_multi_connections.c
@@ -0,0 +1,424 @@
+/*
+ * 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 <string.h>
+
+#include <sys/un.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#include <LongBow/unit-test.h>
+
+
+#include <ccnx/api/control/cpi_ControlMessage.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Security.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <ccnx/transport/transport_rta/config/config_All.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_Commands.c>
+#include <ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.h>
+
+#include "../../test_tools/bent_pipe.h"
+#include <ccnx/transport/test_tools/traffic_tools.h>
+
+static const char local_name[] = "/tmp/beta";
+static const char alice_keystore_name[] = "/tmp/alice_keystore";
+static const char bob_keystore_name[] = "/tmp/bob_keystore";
+
+static int alice_fd;
+static int bob_fd;
+static TransportContext *transport_context;
+static CCNxTransportConfig *alice_params;
+static CCNxTransportConfig *bob_params;
+
+// reflector for FWD_LOCAL
+static BentPipeState *bentpipe;
+
+static int rnd_fd;
+
+// for statistics
+static double total_delay;
+static double total_bytes_per_sec;
+static unsigned item_count;
+
+// ======================================================
+
+static CCNxTransportConfig *
+MultipleConnections_createParams(const char *local_name, const char *keystore_name, const char *keystore_passwd, const char *nonce)
+{
+ assertNotNull(local_name, "Got null keystore name\n");
+ assertNotNull(keystore_name, "Got null keystore name\n");
+ assertNotNull(keystore_passwd, "Got null keystore passwd\n");
+
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+
+ apiConnector_ProtocolStackConfig(
+ tlvCodec_ProtocolStackConfig(
+ localForwarder_ProtocolStackConfig(
+ protocolStack_ComponentsConfigArgs(stackConfig,
+ apiConnector_GetName(),
+ tlvCodec_GetName(),
+ localForwarder_GetName(),
+ NULL)
+ )));
+
+ CCNxConnectionConfig *connConfig = apiConnector_ConnectionConfig(
+ tlvCodec_ConnectionConfig(
+ localForwarder_ConnectionConfig(ccnxConnectionConfig_Create(), local_name)));
+
+ publicKeySigner_ConnectionConfig(connConfig, keystore_name, keystore_passwd);
+
+
+ // add the special nonce
+ PARCJSONValue *value = parcJSONValue_CreateFromCString(nonce);
+ ccnxStackConfig_Add(stackConfig, "nonce", value);
+ parcJSONValue_Release(&value);
+
+ CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig);
+ ccnxStackConfig_Release(&stackConfig);
+
+ return result;
+}
+
+/**
+ * @function sendRandomObject
+ * @abstract Sends a content object over the given socket.
+ * @discussion
+ * The payload of the content object is a "struct timeval" for timing purposes.
+ *
+ * @param Transport socket to use
+ * @return A copy of the content object sent
+ */
+static CCNxContentObject *
+sendRandomObject(int output_fd, int fixed_size)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ if (fixed_size < (int) sizeof(tv)) {
+ fixed_size = sizeof(tv);
+ }
+
+ uint8_t *buffer = parcMemory_Allocate(fixed_size);
+ assertNotNull(buffer, "parcMemory_Allocate(%d) returned NULL", fixed_size);
+ memcpy(buffer, (uint8_t *) &tv, sizeof(tv));
+
+ PARCBuffer *contents = parcBuffer_Flip(parcBuffer_CreateFromArray(buffer, fixed_size));
+ CCNxContentObject *object = trafficTools_CreateContentObjectWithPayload(contents);
+ parcBuffer_Release(&contents);
+
+ // Return value not checked.
+ // This creates a reference to object, so we still hold the memory and can return it
+ CCNxMetaMessage *meta = ccnxMetaMessage_CreateFromContentObject(object);
+ Transport_Send(output_fd, meta);
+ ccnxMetaMessage_Release(&meta);
+
+ parcMemory_Deallocate((void **) &buffer);
+
+ // truth_co and truth_msg will be freed by Transport_Send
+ return object;
+}
+
+/**
+ * @function recvAndCompare
+ * @abstract Block on receiving a message on the input_fd, then assert its the same as the truth_obj.
+ * @discussion
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+static bool
+recvAndCompare(int input_fd, CCNxContentObject *truth_obj)
+{
+ struct timeval now, *then, delta;
+
+ CCNxMetaMessage *test_msg;
+ int res = Transport_Recv(input_fd, &test_msg);
+
+ assertTrue(res == 0, "got error from Transport_Recv (%d)", res);
+
+ // We can't directly compare the two dictionaries with CCNxTlvDictionary_Equals(),
+ // because the test_obj that we read in was signed in the Transport when
+ // it was sent. So the dictionaries are different.
+
+ // So, instead, compare the payload - which should have the time at which the ContentObject
+ // was created.
+
+ CCNxContentObject *testObject = ccnxMetaMessage_GetContentObject(test_msg);
+ PARCBuffer *contentsA = ccnxContentObject_GetPayload(testObject);
+ PARCBuffer *contentsB = ccnxContentObject_GetPayload(truth_obj);
+ assertTrue(parcBuffer_Equals(contentsA, contentsB), "Payloads do not compare");
+
+ then = (struct timeval *) parcBuffer_Overlay(contentsA, 0);
+
+ gettimeofday(&now, NULL);
+ timersub(&now, then, &delta);
+
+ double delay = delta.tv_sec + 1E-6 * delta.tv_usec;
+ double bytes_per_sec = parcBuffer_Remaining(parcBuffer_Rewind(contentsA)) / delay;
+
+ total_delay += delay;
+ total_bytes_per_sec += bytes_per_sec;
+ item_count++;
+
+ ccnxMetaMessage_Release(&test_msg);
+ return true;
+}
+
+static void
+assertConnectionOpen(int fd)
+{
+ // wait for the CONNECTION_OPEN messages
+ CCNxMetaMessage *firstMessage;
+ Transport_Recv(fd, &firstMessage);
+
+ assertTrue(ccnxMetaMessage_IsControl(firstMessage), "Expected first message to be a control message");
+
+ CCNxControl *control = ccnxMetaMessage_GetControl(firstMessage);
+
+ if (ccnxControl_IsNotification(control)) {
+ NotifyStatus *status = ccnxControl_GetNotifyStatus(control);
+
+ assertTrue(notifyStatus_IsConnectionOpen(status), "Expected notifyStatus_IsConnectionOpen to be true");
+
+ notifyStatus_Release(&status);
+ }
+
+ ccnxMetaMessage_Release(&firstMessage);
+}
+
+static void
+stackSetup(const char *alice_nonce, const char *bob_nonce)
+{
+ unlink(local_name);
+
+ bentpipe = bentpipe_Create(local_name);
+ bentpipe_SetChattyOutput(bentpipe, false);
+ bentpipe_Start(bentpipe);
+
+ transport_context = Transport_Create(TRANSPORT_RTA);
+
+ assertNotNull(transport_context, "transportRta_Create() returned null");
+
+ unlink(alice_keystore_name);
+ unlink(bob_keystore_name);
+
+ bool success = parcPkcs12KeyStore_CreateFile(alice_keystore_name, "23456", "alice", 1024, 30);
+ assertTrue(success, "parcPkcs12Store_CreateFile() failed.");
+ success = parcPkcs12KeyStore_CreateFile(bob_keystore_name, "34567", "bob", 2048, 15);
+ assertTrue(success, "parcPkcs12Store_CreateFile() failed.");
+
+ alice_params = MultipleConnections_createParams(local_name, alice_keystore_name, "23456", alice_nonce);
+ bob_params = MultipleConnections_createParams(local_name, bob_keystore_name, "34567", bob_nonce);
+
+ // open a connection, this will cause accpet() to fire
+ alice_fd = Transport_Open(alice_params);
+ bob_fd = Transport_Open(bob_params);
+
+ assertFalse(alice_fd < 0, "Transport_Open returned error");
+ assertFalse(bob_fd < 0, "Transport_Open returned error");
+
+ assertConnectionOpen(alice_fd);
+ assertConnectionOpen(bob_fd);
+}
+
+static void
+stackTearDown(const char *alice_nonce, const char *bob_nonce)
+{
+ assertTrue(unlink(alice_keystore_name) == 0 || errno == ENOENT,
+ "Unable to unlink the file %s: %s", alice_keystore_name, strerror(errno));
+
+ assertTrue(unlink(bob_keystore_name) == 0 || errno == ENOENT,
+ "Unable to unlink the file %s: %s", bob_keystore_name, strerror(errno));
+
+ Transport_Destroy(&transport_context);
+ bentpipe_Stop(bentpipe);
+ bentpipe_Destroy(&bentpipe);
+
+ ccnxTransportConfig_Destroy(&alice_params);
+ ccnxTransportConfig_Destroy(&bob_params);
+}
+
+#include <parc/algol/parc_Object.h>
+
+/**
+ * @function ping
+ * @abstract Send a message from one socket to another socket
+ * @discussion
+ * Send a content object from one socket to another, then esure the
+ * unsigned parts of the received message compare to the sent message.
+ *
+ * There's a minimum size (sizeof struct timeval). If the fixed_size is
+ * larger than that minimum, we'll pad out to the fixed size.
+ *
+ * @param fixed_size is the payload content size.
+ * @return <#return#>
+ */
+static bool
+ping(int from_fd, int to_fd, int fixed_size)
+{
+ CCNxContentObject *object = sendRandomObject(from_fd, fixed_size);
+ bool success = recvAndCompare(to_fd, object);
+ assertTrue(success, "sent and received didn't compare!\n");
+ ccnxContentObject_Release(&object);
+ return success;
+}
+/**
+ * use -1 for random size, othewise anything larger than 16 works
+ * for the payload size
+ */
+static void
+playPingPong(int fixed_size)
+{
+ int loops = 10;
+ while (loops-- > 0) {
+ // send down alice and up bob, then bob to alice
+ ping(alice_fd, bob_fd, fixed_size);
+ ping(bob_fd, alice_fd, fixed_size);
+ }
+}
+
+// ======================================================
+
+
+LONGBOW_TEST_RUNNER(MultipleConnections)
+{
+ LONGBOW_RUN_TEST_FIXTURE(SameStack);
+ LONGBOW_RUN_TEST_FIXTURE(DifferentStacks);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(MultipleConnections)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ rnd_fd = open("/dev/urandom", O_RDONLY);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(MultipleConnections)
+{
+ close(rnd_fd);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+
+/*
+ * Same Stack tests multiple connections within the same
+ * protocol stack
+ */
+
+LONGBOW_TEST_FIXTURE(SameStack)
+{
+ LONGBOW_RUN_TEST_CASE(SameStack, alice_bob_pingpong);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(SameStack)
+{
+ parcSecurity_Init();
+ stackSetup("apple", "apple");
+
+ total_delay = total_bytes_per_sec = 0.0;
+ item_count = 0;
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(SameStack)
+{
+ longBowDebug("average delay %.6f sec, avg bytes/sec %.3f\n",
+ total_delay / item_count, total_bytes_per_sec / item_count);
+
+ stackTearDown("apple", "apple");
+
+ parcSecurity_Fini();
+
+ if (parcMemory_Outstanding() != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(SameStack, alice_bob_pingpong)
+{
+ playPingPong(8192);
+}
+
+// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+
+/*
+ * DifferentStacks tests multiple connections through
+ * different stacks in the same transport
+ */
+
+LONGBOW_TEST_FIXTURE(DifferentStacks)
+{
+ LONGBOW_RUN_TEST_CASE(DifferentStacks, alice_bob_pingpong);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(DifferentStacks)
+{
+ parcSecurity_Init();
+ stackSetup("apple", "oranges");
+ total_delay = total_bytes_per_sec = 0.0;
+ item_count = 0;
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(DifferentStacks)
+{
+ stackTearDown("apple", "oranges");
+
+ parcSecurity_Fini();
+
+ if (parcMemory_Outstanding() != 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(DifferentStacks, alice_bob_pingpong)
+{
+ playPingPong(-1);
+}
+
+// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(MultipleConnections);
+ exit(longBowMain(argc, argv, testRunner, NULL));
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Commands.c b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Commands.c
new file mode 100644
index 00000000..4f4d7cb0
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Commands.c
@@ -0,0 +1,381 @@
+/*
+ * 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 "../rta_Commands.c"
+
+#include "../core/components.h"
+#include <ccnx/transport/transport_rta/config/config_All.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <strings.h>
+
+static TransportConfig *
+Test_createParams(const char *local_name)
+{
+ assertNotNull(local_name, "%s got null keystore name\n", __func__);
+
+ ConnectionConfig *connConfig = apiConnector_ConnectionConfig(localForwarder_ConnectionConfig(ccnxConnectionConfig_Create(), local_name));
+
+ CCNxStackConfig *stackConfig = apiConnector_ProtocolStackConfig(
+ localForwarder_ProtocolStackConfig(
+ protocolStack_ComponentsConfigArgs(
+ ccnxStackConfig_Create(), apiConnector_GetName(), localForwarder_GetName(), NULL)));
+
+ return transportConfig_Create(stackConfig, connConfig);
+}
+
+LONGBOW_TEST_RUNNER(rta_Commands)
+{
+ // 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(rta_Commands)
+{
+ 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_Commands)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Close);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_CreateStack);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_DestroyStack);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetClose);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetCreateStack);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetDestroyStack);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetOpen);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetType);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Open);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Read_Write);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Shutdown);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_CreateTransmitStatistics);
+ LONGBOW_RUN_TEST_CASE(Global, CommandTransmitStatistics_FromJSON);
+}
+
+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, rtaCommand_Close)
+{
+ CommandClose commmandClose = { .api_fd = 7 };
+ char *truth = "{ \"RTA\" : { \"CLOSE\" : 7 } }";
+ PARCJSON *truth_json = parcJSON_ParseString(truth);
+ char *truth_formatted = ccnxJson_ToString(truth_json);
+ char *test;
+
+ RtaCommand *command = rtaCommand_Close(commmandClose);
+
+ assertTrue(command->type == RTA_COMMAND_CLOSE, "Type not RTA_COMMAND_CLOSE");
+
+ test = ccnxJson_ToString(command->command);
+ assertTrue(strcasecmp(test, truth_formatted) == 0,
+ "JSON does not match\nexpected: %s\ngot: %s\n",
+ truth_formatted, test);
+
+ rtaCommand_Destroy(&command);
+ parcJSON_Release(&truth_json);
+ parcMemory_Deallocate((void **) &test);
+ parcMemory_Deallocate((void **) &truth_formatted);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_CreateStack)
+{
+ TransportConfig *params = Test_createParams("/tmp/fwd");
+ CCNxStackConfig *stackConfig = transportConfig_GetProtocolStackConfig(params);
+ char *params_str = ccnxJson_ToString(ccnxStackConfig_GetJson(stackConfig));
+
+ CommandCreateStack commandCreateStack = { .stack_id = 9, .params = ccnxStackConfig_GetJson(stackConfig) };
+ char *truth = "{ \"RTA\" : { \"CREATE STACK\" : 9, \"PARAMS\" : %s } }";
+ char buffer[1024];
+
+ sprintf(buffer, truth, params_str);
+
+ PARCJSON *truth_json = parcJSON_ParseString(buffer);
+ char *truth_formatted = ccnxJson_ToString(truth_json);
+ char *test;
+
+ RtaCommand *command = rtaCommand_CreateStack(commandCreateStack);
+
+ assertTrue(command->type == RTA_COMMAND_CREATESTACK, "Type not RTA_COMMAND_CREATESTACK");
+
+ test = ccnxJson_ToString(command->command);
+ assertTrue(strcasecmp(test, truth_formatted) == 0,
+ "JSON does not match\nexpected: %s\ngot: %s\n",
+ truth_formatted, test);
+
+ rtaCommand_Destroy(&command);
+ parcJSON_Release(&truth_json);
+ transportConfig_Destroy(&params);
+ parcMemory_Deallocate((void **) &test);
+ parcMemory_Deallocate((void **) &truth_formatted);
+ parcMemory_Deallocate((void **) &params_str);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_DestroyStack)
+{
+ CommandDestroyStack commandDestroyStack = { .stack_id = 2 };
+ char *truth = "{ \"RTA\" : { \"DESTROY STACK\" : 2 } }";
+ PARCJSON *truth_json = parcJSON_ParseString(truth);
+ char *truth_formatted = ccnxJson_ToString(truth_json);
+ char *test;
+
+ RtaCommand *command = rtaCommand_DestroyStack(commandDestroyStack);
+
+ assertTrue(command->type == RTA_COMMAND_DESTROYSTACK, "Type not RTA_COMMAND_DESTROYSTACK");
+
+ test = ccnxJson_ToString(command->command);
+ assertTrue(strcasecmp(test, truth_formatted) == 0,
+ "JSON does not match\nexpected: %s\ngot: %s\n",
+ truth_formatted, test);
+
+ rtaCommand_Destroy(&command);
+ parcJSON_Release(&truth_json);
+ parcMemory_Deallocate((void **) &test);
+ parcMemory_Deallocate((void **) &truth_formatted);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetClose)
+{
+ CommandClose commmandClose = { .api_fd = 7 };
+ CommandClose test;
+
+ RtaCommand *command = rtaCommand_Close(commmandClose);
+ rtaCommand_GetClose(command, &test);
+ assertTrue(memcmp(&commmandClose, &test, sizeof(CommandClose)) == 0, "structures do not match");
+ rtaCommand_Destroy(&command);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetCreateStack)
+{
+ TransportConfig *params = Test_createParams("/tmp/fwd");
+ CCNxStackConfig *stackConfig = transportConfig_GetProtocolStackConfig(params);
+
+ CommandCreateStack commandCreateStack = { .stack_id = 9, .params = ccnxStackConfig_GetJson(stackConfig) };
+ CommandCreateStack test;
+
+ RtaCommand *command = rtaCommand_CreateStack(commandCreateStack);
+ rtaCommand_GetCreateStack(command, &test);
+
+ assertTrue(test.stack_id == 9, "Wrong stack id, expected %d got %d", 9, test.stack_id);
+
+ char *truth_params = ccnxJson_ToString(ccnxStackConfig_GetJson(stackConfig));
+ char *test_params = ccnxJson_ToString(test.params);
+ assertTrue(strcasecmp(truth_params, test_params) == 0, "params strings did not match");
+
+ parcMemory_Deallocate((void **) &truth_params);
+ parcMemory_Deallocate((void **) &test_params);
+ rtaCommand_Destroy(&command);
+ transportConfig_Destroy(&params);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetDestroyStack)
+{
+ CommandDestroyStack commandDestroyStack = { .stack_id = 133434 };
+ CommandDestroyStack test;
+
+ RtaCommand *command = rtaCommand_DestroyStack(commandDestroyStack);
+ rtaCommand_GetDestroyStack(command, &test);
+ assertTrue(memcmp(&commandDestroyStack, &test, sizeof(CommandDestroyStack)) == 0, "structures do not match");
+ rtaCommand_Destroy(&command);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetOpen)
+{
+ TransportConfig *params = Test_createParams("/tmp/fwd");
+ CCNxStackConfig *stackConfig = transportConfig_GetProtocolStackConfig(params);
+
+ CommandOpen commandOpen = { .stack_id = 9, .api_fd = 77, .transport_fd = 102, .params = ccnxStackConfig_GetJson(stackConfig) };
+ CommandOpen test;
+ RtaCommand *command = rtaCommand_Open(commandOpen);
+ rtaCommand_GetOpen(command, &test);
+
+ assertTrue(test.stack_id == 9, "Wrong stack id, expected %d got %d", 9, test.stack_id);
+ assertTrue(test.api_fd == 77, "Wrong api_fd, expected %d got %d", 77, test.api_fd);
+ assertTrue(test.transport_fd == 102, "Wrong transport_fd, expected %d got %d", 102, test.transport_fd);
+
+ char *truth_params = ccnxJson_ToString(ccnxStackConfig_GetJson(stackConfig));
+ char *test_params = ccnxJson_ToString(test.params);
+ assertTrue(strcasecmp(truth_params, test_params) == 0, "params strings did not match");
+
+ parcMemory_Deallocate((void **) &truth_params);
+ parcMemory_Deallocate((void **) &test_params);
+ rtaCommand_Destroy(&command);
+ transportConfig_Destroy(&params);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetType)
+{
+ CommandDestroyStack commandDestroyStack = { .stack_id = 2 };
+ RtaCommand *command = rtaCommand_DestroyStack(commandDestroyStack);
+ assertTrue(rtaCommand_GetType(command) == RTA_COMMAND_DESTROYSTACK, "Type not RTA_COMMAND_DESTROYSTACK");
+ rtaCommand_Destroy(&command);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_Open)
+{
+ TransportConfig *params = Test_createParams("/tmp/fwd");
+ CCNxStackConfig *stackConfig = transportConfig_GetProtocolStackConfig(params);
+
+ char *params_str = ccnxJson_ToString(ccnxStackConfig_GetJson(stackConfig));
+
+ CommandOpen commandOpen = { .stack_id = 9, .api_fd = 77, .transport_fd = 102, .params = ccnxStackConfig_GetJson(stackConfig) };
+ char *truth = "{ \"RTA\" : { \"OPEN\" : [9, 77, 102], \"PARAMS\" : %s } }";
+ char buffer[1024];
+
+ sprintf(buffer, truth, params_str);
+
+ PARCJSON *truth_json = parcJSON_ParseString(buffer);
+ char *truth_formatted = ccnxJson_ToString(truth_json);
+ char *test;
+
+ RtaCommand *command = rtaCommand_Open(commandOpen);
+
+ assertTrue(command->type == RTA_COMMAND_OPEN, "Type not RTA_COMMAND_OPEN");
+
+ test = ccnxJson_ToString(command->command);
+ assertTrue(strcasecmp(test, truth_formatted) == 0,
+ "JSON does not match\nexpected: %s\ngot: %s\n",
+ truth_formatted, test);
+
+ rtaCommand_Destroy(&command);
+ parcJSON_Release(&truth_json);
+ transportConfig_Destroy(&params);
+ parcMemory_Deallocate((void **) &test);
+ parcMemory_Deallocate((void **) &truth_formatted);
+ parcMemory_Deallocate((void **) &params_str);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_Read_Write)
+{
+ int fds[2];
+ pipe(fds);
+
+ CommandDestroyStack commandDestroyStack = { .stack_id = 2 };
+ RtaCommand *command = rtaCommand_DestroyStack(commandDestroyStack);
+ rtaCommand_Write(command, fds[1]);
+ RtaCommand *test_command = rtaCommand_Read(fds[0]);
+ CommandDestroyStack test;
+ rtaCommand_GetDestroyStack(test_command, &test);
+ assertTrue(memcmp(&commandDestroyStack, &test, sizeof(commandDestroyStack)) == 0, "memcmp did not match");
+
+ rtaCommand_Destroy(&command);
+ rtaCommand_Destroy(&test_command);
+ close(fds[1]);
+ close(fds[0]);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_Shutdown)
+{
+ char *truth = "{ \"RTA\" : { \"SHUTDOWN\" : 1 } }";
+ PARCJSON *truth_json = parcJSON_ParseString(truth);
+ char *truth_formatted = ccnxJson_ToString(truth_json);
+ char *test;
+
+ RtaCommand *command = rtaCommand_Shutdown();
+
+ assertTrue(command->type == RTA_COMMAND_SHUTDOWN, "Type not RTA_COMMAND_SHUTDOWN");
+
+ test = ccnxJson_ToString(command->command);
+ assertTrue(strcasecmp(test, truth_formatted) == 0,
+ "JSON does not match\nexpected: %s\ngot: %s\n",
+ truth_formatted, test);
+
+ rtaCommand_Destroy(&command);
+ parcJSON_Release(&truth_json);
+ parcMemory_Deallocate((void **) &test);
+ parcMemory_Deallocate((void **) &truth_formatted);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_CreateTransmitStatistics)
+{
+ char *truth = "{ \"RTA\" : { \"TransmitStatistics\" : { \"fileName\": \"/tmp/foo\", \"timeval\" : { "
+ "\"seconds\" : 1, \"microseconds\": 2 } } } }\n";
+
+ PARCJSON *truth_json = parcJSON_ParseString(truth);
+ char *truth_formatted = ccnxJson_ToString(truth_json);
+
+ CommandTransmitStatistics transmitStatistics = {
+ .timeval = { .tv_sec = 1, .tv_usec = 2 },
+ .fileName = "/tmp/foo"
+ };
+
+ RtaCommand *command = CommandTransmitStatistics_ToRtaCommand(transmitStatistics);
+
+ assertTrue(command->type == RTA_COMMAND_TRANSMIT_STATISTICS,
+ "Expected RTA_COMMAND_TRANSMIT_STATISTICS, actual %d", command->type);
+
+ char *test = ccnxJson_ToString(command->command);
+ assertTrue(strcasecmp(test, truth_formatted) == 0,
+ "JSON does not match\nexpected: %s\ngot: %s\n",
+ truth_formatted, test);
+
+ rtaCommand_Destroy(&command);
+ parcJSON_Release(&truth_json);
+ parcMemory_Deallocate((void **) &test);
+ parcMemory_Deallocate((void **) &truth_formatted);
+}
+
+LONGBOW_TEST_CASE(Global, CommandTransmitStatistics_FromJSON)
+{
+ CommandTransmitStatistics transmitStatistics = {
+ .timeval = { .tv_sec = 1, .tv_usec = 2 },
+ .fileName = "/tmp/foo"
+ };
+ RtaCommand *command = CommandTransmitStatistics_ToRtaCommand(transmitStatistics);
+
+ CommandTransmitStatistics actual;
+ CommandTransmitStatistics_FromRtaCommand(command, &actual);
+
+ assertTrue(transmitStatistics.timeval.tv_sec == actual.timeval.tv_sec, "tv_sec failed to be equal");
+ assertTrue(transmitStatistics.timeval.tv_usec == actual.timeval.tv_usec, "tv_usec failed to be equal");
+ assertTrue(strcmp(transmitStatistics.fileName, actual.fileName) == 0, "fileName failed to be equal");
+
+ rtaCommand_Destroy(&command);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_Commands);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Transport.c b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Transport.c
new file mode 100644
index 00000000..9f6f0611
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Transport.c
@@ -0,0 +1,701 @@
+/*
+ * 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 "../rta_Transport.c"
+#include <ccnx/transport/transport_rta/config/config_All.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_private.h>
+#include <ccnx/transport/transport_rta/components/component_Testing.h>
+
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <ccnx/transport/test_tools/traffic_tools.h>
+
+#include <LongBow/unit-test.h>
+
+typedef struct test_data {
+ RTATransport *transport;
+ CCNxMetaMessage *msg;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->transport = rtaTransport_Create();
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ rtaTransport_Destroy(&data->transport);
+ if (data->msg) {
+ ccnxMetaMessage_Release(&data->msg);
+ }
+
+ parcMemory_Deallocate((void **) &data);
+}
+
+static CCNxTransportConfig *
+createSimpleConfig(TestData *data)
+{
+ // API connector -> Testing Lower component
+
+ CCNxStackConfig *stackConfig =
+ testingLower_ProtocolStackConfig(apiConnector_ProtocolStackConfig(ccnxStackConfig_Create()));
+
+ CCNxConnectionConfig *connConfig =
+ testingLower_ConnectionConfig(
+ tlvCodec_ConnectionConfig(
+ apiConnector_ConnectionConfig(
+ ccnxConnectionConfig_Create())));
+
+ protocolStack_ComponentsConfigArgs(stackConfig, apiConnector_GetName(), testingLower_GetName(), NULL);
+
+ CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig);
+ ccnxStackConfig_Release(&stackConfig);
+ return result;
+}
+
+/**
+ * Peek inside the RTA framework's connection table
+ *
+ * We will look inside the RTA framework's thread to find a connection by the API_FD.
+ *
+ * @param [in] data The test data, holding the transport
+ * @param [in] api_fd The API FD to lookup
+ * @param [in] usec_timeout How long to busy wait looking in the connection table (micro seconds)
+ *
+ * @return NULL It was not in the table after the timeout period
+ * @return non-null The connection corresponding to api_fd
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static RtaConnection *
+lookupRtaConnectionInsideFramework(TestData *data, int api_fd, unsigned usec_timeout)
+{
+ // busy loop looking for connection to give RTA thread time to process it.
+ // Remember, we're operating in the "API" thread when issuing these commands.
+ struct timeval t0;
+ long timer_usec = 0;
+ gettimeofday(&t0, NULL);
+ bool timeout = false;
+ RtaConnection *conn = NULL;
+ while (conn == NULL && !timeout) {
+ usleep(500);
+ conn = rtaConnectionTable_GetByApiFd(data->transport->framework->connectionTable, api_fd);
+ struct timeval t1;
+ gettimeofday(&t1, NULL);
+ timersub(&t1, &t0, &t1);
+ timer_usec = t1.tv_sec * 1000000 + t1.tv_usec;
+ timeout = timer_usec > usec_timeout ? true : false;
+ }
+
+ if (conn) {
+ printf("Found connection %p after %.6f seconds\n", (void *) conn, timer_usec * 1E-6);
+ }
+
+ return conn;
+}
+
+/**
+ * Wait for a connection to go away
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+lookupNullRtaConnectionInsideFramework(TestData *data, int api_fd, unsigned usec_timeout)
+{
+ // busy loop looking for connection to give RTA thread time to process it.
+ // Remember, we're operating in the "API" thread when issuing these commands.
+ struct timeval t0;
+ long timer_usec = 0;
+ gettimeofday(&t0, NULL);
+ bool timeout = false;
+
+ // initialize to non-null
+ RtaConnection *conn = (void *) 1;
+ while (conn != NULL && !timeout) {
+ usleep(500);
+ conn = rtaConnectionTable_GetByApiFd(data->transport->framework->connectionTable, api_fd);
+ struct timeval t1;
+ gettimeofday(&t1, NULL);
+ timersub(&t1, &t0, &t1);
+ timer_usec = t1.tv_sec * 1000000 + t1.tv_usec;
+ timeout = timer_usec > usec_timeout ? true : false;
+ }
+
+ if (conn == NULL) {
+ printf("Found no connection %p after %.6f seconds\n", (void *) conn, timer_usec * 1E-6);
+ }
+
+ // if its null, return true
+ return (conn == NULL);
+}
+
+
+// ==================================================================================
+// Runner
+
+LONGBOW_TEST_RUNNER(rta_Transport)
+{
+ // 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_Transport)
+{
+ 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_Transport)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ==================================================================================
+// Global
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ // These are still static functions, but they are the function pointers used
+ // in the transport function structure. They comprise the public API.
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Close);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Open);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_PassCommand);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Recv_OK);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Recv_WouldBlock);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Send_OK);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Send_WouldBlock);
+
+// LONGBOW_RUN_TEST_CASE(Global, unrecoverable);
+}
+
+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, rtaTransport_Close)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+ int api_fd = rtaTransport_Open(data->transport, config);
+
+ RtaConnection *conn = lookupRtaConnectionInsideFramework(data, api_fd, 1E+6);
+ assertNotNull(conn, "Could not find connection");
+
+ rtaTransport_Close(data->transport, api_fd);
+
+ // now wait until it's gone
+ bool gone = lookupNullRtaConnectionInsideFramework(data, api_fd, 1E+6);
+ assertTrue(gone, "Did not remove connection after 1 second timeout");
+
+ ccnxTransportConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Global, rtaTransport_Create_Destroy)
+{
+ RTATransport *transport = rtaTransport_Create();
+ assertNotNull(transport, "rtaTransport_Create() returns NULL");
+
+ rtaTransport_Destroy(&transport);
+ assertNull(transport, "rtaTransport_Destroy did not null paramter");
+}
+
+LONGBOW_TEST_CASE(Global, rtaTransport_Open)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+ int api_fd = rtaTransport_Open(data->transport, config);
+
+ RtaConnection *conn = lookupRtaConnectionInsideFramework(data, api_fd, 1E+6);
+ assertNotNull(conn, "Could not find connection");
+
+ ccnxTransportConfig_Destroy(&config);
+}
+
+/**
+ * PassCommand sends a user RTA Command over the command channel.
+ * This test will intercept the transport side of the command channel so
+ * we can easily verify the command went through.
+ */
+LONGBOW_TEST_CASE(Global, rtaTransport_PassCommand)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCRingBuffer1x1 *previousRingBuffer = data->transport->commandRingBuffer;
+ PARCNotifier *previousNotifier = data->transport->commandNotifier;
+
+ PARCRingBuffer1x1 *testRingBuffer = parcRingBuffer1x1_Create(32, NULL);
+ PARCNotifier *testNotifier = parcNotifier_Create();
+
+
+ // Insert our new socket pair so we can intercept the commands
+ // No acquire here because we will be resetting them and destroying all in this scope
+ data->transport->commandRingBuffer = testRingBuffer;
+ data->transport->commandNotifier = testNotifier;
+
+ // Create a simple command to send
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ rtaTransport_PassCommand(data->transport, command);
+ rtaCommand_Release(&command);
+
+ RtaCommand *testCommand = rtaCommand_Read(testRingBuffer);
+ assertNotNull(testCommand, "Got null command from the ring buffer.");
+ assertTrue(rtaCommand_IsShutdownFramework(testCommand), "Command not a shutdown framework");
+
+ // All's well
+
+ rtaCommand_Release(&testCommand);
+
+ // now restore the sockets so things close up nicely
+ data->transport->commandRingBuffer = previousRingBuffer;
+ data->transport->commandNotifier = previousNotifier;
+
+ parcRingBuffer1x1_Release(&testRingBuffer);
+ parcNotifier_Release(&testNotifier);
+}
+
+LONGBOW_TEST_CASE(Global, rtaTransport_Recv_OK)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int api_fd, transport_fd;
+
+ _RTASocketPair pair = _rtaTransport_CreateSocketPair(data->transport, 128 * 1024);
+ api_fd = pair.up;
+ transport_fd = pair.down;
+
+ // Set non-blocking flag
+ int flags = fcntl(api_fd, F_GETFL, NULL);
+ assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno);
+ int failure = fcntl(api_fd, F_SETFL, flags | O_NONBLOCK);
+ assertFalse(failure, "fcntl failed to set file descriptor flags (%d)\n", errno);
+
+ char *buffer = "born free, as free as the wind blows";
+ ssize_t nwritten = write(transport_fd, &buffer, sizeof(&buffer));
+ assertTrue(nwritten == sizeof(&buffer), "Wrong write size, expected %zu got %zd", sizeof(&buffer), nwritten);
+
+ CCNxMetaMessage *msg = NULL;
+ TransportIOStatus result = rtaTransport_Recv(data->transport, api_fd, &msg, CCNxStackTimeout_Never);
+ assertTrue(result != TransportIOStatus_Error, "Failed to read a good socket");
+ assertTrue((void *) msg == (void *) buffer, "Read wrong pointer, got %p expected %p", (void *) msg, (void *) buffer);
+
+ close(api_fd);
+ close(transport_fd);
+}
+
+LONGBOW_TEST_CASE(Global, rtaTransport_Recv_WouldBlock)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int api_fd, transport_fd;
+
+ _RTASocketPair pair = _rtaTransport_CreateSocketPair(data->transport, 128 * 1024);
+ api_fd = pair.up;
+ transport_fd = pair.down;
+
+ // Set non-blocking flag
+ int flags = fcntl(api_fd, F_GETFL, NULL);
+ assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno);
+ int failure = fcntl(api_fd, F_SETFL, flags | O_NONBLOCK);
+ assertFalse(failure, "fcntl failed to set file descriptor flags (%d)\n", errno);
+
+ // Don't write anything
+
+ CCNxMetaMessage *msg = NULL;
+ TransportIOStatus result = rtaTransport_Recv(data->transport, api_fd, &msg, CCNxStackTimeout_Immediate);
+ assertTrue(result == TransportIOStatus_Timeout, "Should have returned failure due to blocking");
+
+ close(api_fd);
+ close(transport_fd);
+}
+
+
+/**
+ * This function will receive what the API Connector sends down the stack
+ */
+static void
+mockDowncallRead(PARCEventQueue *queue, PARCEventType type, void *stack)
+{
+ TransportMessage *tm = rtaComponent_GetMessage(queue);
+ assertNotNull(tm, "got null transport message");
+
+ CCNxTlvDictionary *dictionary = transportMessage_GetDictionary(tm);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxWireFormatMessage_GetIoVec(dictionary);
+ const struct iovec *iov = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+
+ // we encapsualted a pointer to this counter inside the wire format
+ unsigned *downcallReadCountPtr = iov[0].iov_base;
+ (*downcallReadCountPtr)++;
+
+ transportMessage_Destroy(&tm);
+}
+
+CCNxCodecNetworkBufferMemoryBlockFunctions memfunc = {
+ .allocator = NULL,
+ .deallocator = NULL
+};
+
+/**
+ * This test does not actually need to receive the message in TestingLower. It could have passed
+ * any socket pair to rtaTransport_Send and inspected the result immediately.
+ */
+LONGBOW_TEST_CASE(Global, rtaTransport_Send_OK)
+{
+ testing_null_ops.downcallRead = mockDowncallRead;
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+ unsigned downcallReadCount = 0;
+
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&memfunc, NULL, sizeof(downcallReadCount), (uint8_t *) &downcallReadCount);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ CCNxTlvDictionary *wire = ccnxWireFormatMessage_FromInterestPacketTypeIoVec(CCNxTlvDictionary_SchemaVersion_V1, vec);
+
+ int api_fd = rtaTransport_Open(data->transport, config);
+
+ CCNxMetaMessage *msg = ccnxMetaMessage_Acquire(wire);
+ bool success = rtaTransport_Send(data->transport, api_fd, msg, CCNxStackTimeout_Never);
+ assertTrue(success, "Got error writing to api_fd %d\n", api_fd);
+ ccnxMetaMessage_Release(&msg);
+
+ // now spin on it
+ unsigned maxTries = 2000; // about 1 second
+ while ((downcallReadCount == 0) && (maxTries > 0)) {
+ maxTries--;
+ usleep(500);
+ }
+
+ printf("Read message after %d tries\n", 2000 - maxTries);
+
+ ccnxTlvDictionary_Release(&wire);
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+
+ ccnxTransportConfig_Destroy(&config);
+}
+
+/**
+ * Fill up the socket with junk, then make sure it would blocks
+ */
+LONGBOW_TEST_CASE(Global, rtaTransport_Send_WouldBlock)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int api_fd, transport_fd;
+
+ _RTASocketPair pair = _rtaTransport_CreateSocketPair(data->transport, 128 * 1024);
+ api_fd = pair.up;
+ transport_fd = pair.down;
+
+ // Set non-blocking flag
+ int flags = fcntl(api_fd, F_GETFL, NULL);
+ assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno);
+ int failure = fcntl(api_fd, F_SETFL, flags | O_NONBLOCK);
+ assertFalse(failure, "fcntl failed to set file descriptor flags (%d)\n", errno);
+
+ // write junk until it would block
+ char buffer[1024];
+ while (write(api_fd, buffer, 1024) > 0) {
+ ;
+ }
+
+ assertTrue(errno == EWOULDBLOCK, "wrote until it would block, but got some other error: (%d) %s", errno, strerror(errno));
+
+ // now call the function to test and make sure it does the right thing
+ // if it would block
+ CCNxTlvDictionary *interest = trafficTools_CreateDictionaryInterest();
+ CCNxMetaMessage *msg = ccnxMetaMessage_CreateFromInterest(interest);
+
+ bool success = rtaTransport_Send(data->transport, api_fd, msg, CCNxStackTimeout_Immediate);
+ printf("success %d, errno %d expected %d\n", success, errno, EWOULDBLOCK);
+
+ assertFalse(success, "Send did not return a failure, even though it would have blocked");
+ assertTrue(errno == EWOULDBLOCK, "wrote until it would block, but got some other error: (%d) %s", errno, strerror(errno));
+
+ ccnxMetaMessage_Release(&msg);
+ ccnxTlvDictionary_Release(&interest);
+
+ close(api_fd);
+ close(transport_fd);
+}
+
+/**
+ * Pass it an invalid socket. This will cause a trap in the send code.
+ */
+LONGBOW_TEST_CASE_EXPECTS(Global, rtaTransport_Send_Error, .event = &LongBowTrapUnrecoverableState)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *interest = trafficTools_CreateDictionaryInterest();
+ data->msg = ccnxMetaMessage_Acquire(interest);
+ ccnxTlvDictionary_Release(&interest);
+
+ rtaTransport_Send(data->transport, 999, data->msg, CCNxStackTimeout_Immediate);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, unrecoverable, .event = &LongBowTrapUnrecoverableState)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *interest = trafficTools_CreateDictionaryInterest();
+ data->msg = ccnxMetaMessage_CreateFromInterest(interest);
+ ccnxTlvDictionary_Release(&interest);
+
+ rtaTransport_Send(NULL, 999, data->msg, CCNxStackTimeout_Immediate);
+
+ ccnxMetaMessage_Release(&(data->msg));
+}
+
+// ==================================================================================
+// Local
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_AddStack);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_GetStack);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_GetStack_Missing);
+
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_CreateSocketPair);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_GetProtocolStackEntry_Exists);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_GetProtocolStackEntry_NotExists);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_AddProtocolStackEntry);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_CreateConnection);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ _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(Local, _rtaTransport_CreateSocketPair)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int a, b;
+
+ _RTASocketPair pair = _rtaTransport_CreateSocketPair(data->transport, 128 * 1024);
+ a = pair.up;
+ b = pair.down;
+ assertFalse(a < 0, "socket a is error: %d", a);
+ assertFalse(b < 0, "socket b is error: %d", b);
+
+ ssize_t nwritten = write(a, &a, sizeof(a));
+ assertTrue(nwritten == sizeof(a), "Wrong write size, expected %zu got %zd", sizeof(a), nwritten);
+
+ int test;
+ ssize_t nread = read(b, &test, sizeof(test));
+ assertTrue(nread == sizeof(test), "Wrong read size, expected %zu got %zd", sizeof(test), nread);
+
+ assertTrue(test == a, "read wrong value, got %d wrote %d", test, a);
+
+ close(a);
+ close(b);
+}
+
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_GetProtocolStackEntry_Exists)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+// uint64_t hash = ccnxStackConfig_HashCode(ccnxTransportConfig_GetStackConfig(config));
+
+ _StackEntry *truth = _rtaTransport_AddStack(data->transport, ccnxTransportConfig_GetStackConfig(config));
+
+ _StackEntry *test = _rtaTransport_GetProtocolStackEntry(data->transport, config);
+
+ assertTrue(test == truth, "Wrong pointer, got %p expected %p", (void *) test, (void *) truth);
+
+ ccnxTransportConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_GetProtocolStackEntry_NotExists)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+ _rtaTransport_AddStack(data->transport, ccnxTransportConfig_GetStackConfig(config));
+
+ // Now create the missing one to lookup
+ // this one will have 2x api connectors listed
+ CCNxStackConfig *missingStackConfig =
+ apiConnector_ProtocolStackConfig(apiConnector_ProtocolStackConfig(ccnxStackConfig_Create()));
+ CCNxConnectionConfig *missingConnConfig = apiConnector_ConnectionConfig(ccnxConnectionConfig_Create());
+
+ CCNxTransportConfig *missingConfig = ccnxTransportConfig_Create(missingStackConfig, missingConnConfig);
+ ccnxStackConfig_Release(&missingStackConfig);
+
+ _StackEntry *test = _rtaTransport_GetProtocolStackEntry(data->transport, missingConfig);
+
+ assertNull(test, "Wrong pointer, got %p expected %p", (void *) test, (void *) NULL);
+ ccnxTransportConfig_Destroy(&missingConfig);
+ ccnxTransportConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_AddProtocolStackEntry)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+ _StackEntry *entry = _rtaTransport_AddProtocolStackEntry(data->transport, config);
+ assertNotNull(entry, "Got null entry from _rtaTransport_AddProtocolStackEntry");
+
+ ccnxTransportConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_CreateConnection)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+ _StackEntry *entry = _rtaTransport_AddProtocolStackEntry(data->transport, config);
+
+ _RTASocketPair pair = _rtaTransport_CreateSocketPair(data->transport, 128 * 1024);
+
+ _rtaTransport_CreateConnection(data->transport, config, entry, pair);
+
+ // wait up to 1 second
+ RtaConnection *conn = lookupRtaConnectionInsideFramework(data, pair.up, 1E+6);
+ assertNotNull(conn, "Could not find connection in connection table, timeout at %.6f seconds", 1.0);
+
+ ccnxTransportConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_AddStack)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+ _StackEntry *entry = _rtaTransport_AddStack(data->transport, stackConfig);
+
+ uint64_t hash = ccnxStackConfig_HashCode(stackConfig);
+ _StackEntry *test = _rtaTransport_GetStack(data->transport, hash);
+ assertTrue(test == entry, "Wrong pointer, got %p expected %p", (void *) test, (void *) entry);
+
+ ccnxStackConfig_Release(&stackConfig);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_GetStack)
+{
+ struct test_vector {
+ uint64_t hash;
+ int stackid;
+ _StackEntry *entry;
+ } vector[] = {
+ { .hash = 20, .stackid = 30, .entry = NULL },
+ { .hash = 10, .stackid = 77, .entry = NULL },
+ { .hash = 990, .stackid = 31, .entry = NULL },
+ { .hash = 0, .stackid = 0, .entry = NULL },
+ };
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+
+ char key[10];
+ for (int i = 0; vector[i].hash != 0; i++) {
+ sprintf(key, "key%d", i);
+ PARCJSONValue *json = parcJSONValue_CreateFromNULL();
+ ccnxStackConfig_Add(stackConfig, key, json);
+ parcJSONValue_Release(&json);
+ vector[i].hash = ccnxStackConfig_HashCode(stackConfig);
+ vector[i].entry = _rtaTransport_AddStack(data->transport, stackConfig);
+ }
+ ccnxStackConfig_Release(&stackConfig);
+
+ // now look them up
+ for (int i = 0; vector[i].hash != 0; i++) {
+ _StackEntry *test = _rtaTransport_GetStack(data->transport, vector[i].hash);
+ assertTrue(test == vector[i].entry, "Wrong pointer, got %p expected %p", (void *) test, (void *) vector[i].entry);
+ }
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_GetStack_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+ _rtaTransport_AddStack(data->transport, stackConfig);
+
+ PARCJSONValue *json = parcJSONValue_CreateFromNULL();
+ ccnxStackConfig_Add(stackConfig, "someKey", json);
+ parcJSONValue_Release(&json);
+
+ _StackEntry *test = _rtaTransport_GetStack(data->transport, ccnxStackConfig_HashCode(stackConfig));
+
+ ccnxStackConfig_Release(&stackConfig);
+ assertNull(test, "Wrong pointer, got %p expected %p", (void *) test, NULL);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_Transport);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/cmake/Modules/FindCCNX_Common.cmake b/libccnx-transport-rta/cmake/Modules/FindCCNX_Common.cmake
new file mode 100644
index 00000000..2629c160
--- /dev/null
+++ b/libccnx-transport-rta/cmake/Modules/FindCCNX_Common.cmake
@@ -0,0 +1,39 @@
+########################################
+#
+# Find the Libparc libraries and includes
+# This module sets:
+# CCNX_COMMON_FOUND: True if Libparc was found
+# CCNX_COMMON_LIBRARY: The Libparc library
+# CCNX_COMMON_LIBRARIES: The Libparc library and dependencies
+# CCNX_COMMON_INCLUDE_DIR: The Libparc include dir
+#
+
+set(CCNX_COMMON_SEARCH_PATH_LIST
+ ${CCNX_COMMON_HOME}
+ $ENV{CCNX_COMMON_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(CCNX_COMMON_INCLUDE_DIR ccnx/common/libccnxCommon_About.h
+ HINTS ${CCNX_COMMON_SEARCH_PATH_LIST}
+ PATH_SUFFIXES include
+ DOC "Find the Libccnx-common includes" )
+
+find_library(CCNX_COMMON_LIBRARY NAMES ccnx_common
+ HINTS ${CCNX_COMMON_SEARCH_PATH_LIST}
+ PATH_SUFFIXES lib
+ DOC "Find the Libccnx-common libraries" )
+
+set(CCNX_COMMON_LIBRARIES ${CCNX_COMMON_LIBRARY})
+set(CCNX_COMMON_INCLUDE_DIRS ${CCNX_COMMON_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CCNX_Common DEFAULT_MSG CCNX_COMMON_LIBRARY CCNX_COMMON_INCLUDE_DIR)
diff --git a/libccnx-transport-rta/cmake/Modules/FindLibEvent.cmake b/libccnx-transport-rta/cmake/Modules/FindLibEvent.cmake
new file mode 100644
index 00000000..2d1ca4fe
--- /dev/null
+++ b/libccnx-transport-rta/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-transport-rta/cmake/Modules/FindLibparc.cmake b/libccnx-transport-rta/cmake/Modules/FindLibparc.cmake
new file mode 100644
index 00000000..02835161
--- /dev/null
+++ b/libccnx-transport-rta/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-transport-rta/cmake/Modules/FindLongBow.cmake b/libccnx-transport-rta/cmake/Modules/FindLongBow.cmake
new file mode 100644
index 00000000..e35888eb
--- /dev/null
+++ b/libccnx-transport-rta/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-transport-rta/cmake/Modules/FindUncrustify.cmake b/libccnx-transport-rta/cmake/Modules/FindUncrustify.cmake
new file mode 100644
index 00000000..e53f65fe
--- /dev/null
+++ b/libccnx-transport-rta/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-transport-rta/cmake/Modules/detectCacheSize.cmake b/libccnx-transport-rta/cmake/Modules/detectCacheSize.cmake
new file mode 100644
index 00000000..469d2627
--- /dev/null
+++ b/libccnx-transport-rta/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-transport-rta/cmake/Modules/version.cmake b/libccnx-transport-rta/cmake/Modules/version.cmake
new file mode 100644
index 00000000..74831674
--- /dev/null
+++ b/libccnx-transport-rta/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-transport-rta/cmake/get_version.sh b/libccnx-transport-rta/cmake/get_version.sh
new file mode 100755
index 00000000..34c6ddb2
--- /dev/null
+++ b/libccnx-transport-rta/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-transport-rta/documentation/.gitignore b/libccnx-transport-rta/documentation/.gitignore
new file mode 100644
index 00000000..bb5d033a
--- /dev/null
+++ b/libccnx-transport-rta/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-transport-rta/documentation/Makefile.am b/libccnx-transport-rta/documentation/Makefile.am
new file mode 100644
index 00000000..dafe126f
--- /dev/null
+++ b/libccnx-transport-rta/documentation/Makefile.am
@@ -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.
+#
+
+
+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-transport-rta/documentation/Makefile.notautomake b/libccnx-transport-rta/documentation/Makefile.notautomake
new file mode 100644
index 00000000..48080b75
--- /dev/null
+++ b/libccnx-transport-rta/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-transport-rta/documentation/doxygen-libccnx_api_control.logcd b/libccnx-transport-rta/documentation/doxygen-libccnx_api_control.logcd
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/libccnx-transport-rta/documentation/doxygen-libccnx_api_control.logcd
diff --git a/libccnx-transport-rta/documentation/libccnx-stage1.doxygen b/libccnx-transport-rta/documentation/libccnx-stage1.doxygen
new file mode 100644
index 00000000..17ab6b83
--- /dev/null
+++ b/libccnx-transport-rta/documentation/libccnx-stage1.doxygen
@@ -0,0 +1,2425 @@
+# 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 = libccnx-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/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 =
+
+# 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 = 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 = NO
+
+# 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 = NO
+
+#---------------------------------------------------------------------------
+# 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
+
+
+#TAGFILES = libccnx_api_notify.doctags=../../libccnx_api_notify-documentation/html
+# libccnx_api_portal.doctags=../../libccnx_api_portal-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.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-transport-rta/documentation/libccnx-stage2.doxygen b/libccnx-transport-rta/documentation/libccnx-stage2.doxygen
new file mode 100644
index 00000000..0f65e61f
--- /dev/null
+++ b/libccnx-transport-rta/documentation/libccnx-stage2.doxygen
@@ -0,0 +1,2426 @@
+# 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 = libccnx-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/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 = ../ccnx/common/internal
+
+
+# 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
+
+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=../../../../Libparc/documentation/libparc-documentation/html \
+# ../../Longbow/documentation/longbow.doctags=../../../../Longbow/documentation/longbow-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.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-transport-rta/documentation/libccnx_api_control-stage1.doxygen b/libccnx-transport-rta/documentation/libccnx_api_control-stage1.doxygen
new file mode 100644
index 00000000..7b52c73b
--- /dev/null
+++ b/libccnx-transport-rta/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-transport-rta/documentation/libccnx_api_control-stage2.doxygen b/libccnx-transport-rta/documentation/libccnx_api_control-stage2.doxygen
new file mode 100644
index 00000000..55293941
--- /dev/null
+++ b/libccnx-transport-rta/documentation/libccnx_api_control-stage2.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 = 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 \
+
+
+
+# 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-transport-rta/documentation/libccnx_api_notify-stage1.doxygen b/libccnx-transport-rta/documentation/libccnx_api_notify-stage1.doxygen
new file mode 100644
index 00000000..0629dbdd
--- /dev/null
+++ b/libccnx-transport-rta/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-transport-rta/documentation/libccnx_api_notify-stage2.doxygen b/libccnx-transport-rta/documentation/libccnx_api_notify-stage2.doxygen
new file mode 100644
index 00000000..7d327785
--- /dev/null
+++ b/libccnx-transport-rta/documentation/libccnx_api_notify-stage2.doxygen
@@ -0,0 +1,2418 @@
+# 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 \
+
+
+# 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-transport-rta/documentation/libccnx_api_portal-stage1.doxygen b/libccnx-transport-rta/documentation/libccnx_api_portal-stage1.doxygen
new file mode 100644
index 00000000..edf05ec0
--- /dev/null
+++ b/libccnx-transport-rta/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-transport-rta/documentation/libccnx_api_portal-stage2.doxygen b/libccnx-transport-rta/documentation/libccnx_api_portal-stage2.doxygen
new file mode 100644
index 00000000..3b069c21
--- /dev/null
+++ b/libccnx-transport-rta/documentation/libccnx_api_portal-stage2.doxygen
@@ -0,0 +1,2421 @@
+# 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 \
+
+
+# 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-transport-rta/documentation/librta-stage1.doxygen b/libccnx-transport-rta/documentation/librta-stage1.doxygen
new file mode 100644
index 00000000..f5b73e8b
--- /dev/null
+++ b/libccnx-transport-rta/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-transport-rta/documentation/librta-stage2.doxygen b/libccnx-transport-rta/documentation/librta-stage2.doxygen
new file mode 100644
index 00000000..3df9cb11
--- /dev/null
+++ b/libccnx-transport-rta/documentation/librta-stage2.doxygen
@@ -0,0 +1,2418 @@
+# 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 \
+
+
+# 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-transport-rta/documentation/stylesheet.css b/libccnx-transport-rta/documentation/stylesheet.css
new file mode 100644
index 00000000..fb5cda7c
--- /dev/null
+++ b/libccnx-transport-rta/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;
+}